// bslx_testinstream.t.cpp                                            -*-C++-*-
#include <bslx_testinstream.h>
#include <bslx_testoutstream.h>                 // for testing only

#include <bslma_defaultallocatorguard.h>
#include <bslma_testallocator.h>

#include <bsls_assert.h>
#include <bsls_asserttest.h>
#include <bsls_bsltestutil.h>

#include <bsl_cstddef.h>
#include <bsl_cstdlib.h>
#include <bsl_cstdio.h>
#include <bsl_cstring.h>
#include <bsl_iostream.h>
#include <bsl_sstream.h>
#include <bsl_string.h>

using namespace BloombergLP;
using namespace bsl;
using namespace bslx;

// ============================================================================
//                                 TEST PLAN
// ----------------------------------------------------------------------------
//                                 Overview
//                                 --------
// We are testing a "test" implementation of the BDEX unexternalization
// protocol.  This implementation is designed to consume extra "informational
// data" in a data stream generated by a corresponding "test" implementation of
// the BDEX externalization protocol.  The "informational data" allows an
// object to identify the type (and size, for arrays) of the actual data.
//
// For each input method, we must verify the placement of the next-input-byte-
// position cursor and the alignment of byte values, as in the "normal"
// implementation.  In addition, we must verify that "informational data" is
// read and used to detect invalid data.  We accomplish these goals by
// configuring data streams containing either valid or invalid data, and verify
// the "unexternalized" values as well as the validity of the stream objects.
//
// We must also verify that when a stream is configured with a non-negative
// input limit, each input method correctly modifies the input limit and throws
// an exception when the input limit transitions from 0 to -1.  We achieve this
// goal by configuring test input stream objects with varying input limit
// values and invoke each input method repeatedly to ensure that exceptions are
// thrown when expected.
// ----------------------------------------------------------------------------
// [ 3] TestInStream();
// [ 3] TestInStream(const char *buffer, bsl::size_t numBytes);
// [ 3] TestInStream(const bslstl::StringRef& srcData);
// [ 3] ~TestInStream();
// [29] getLength(int& variable);
// [29] getVersion(int& variable);
// [13] getInt64(bsls::Types::Int64& variable);
// [13] getUint64(bsls::Types::Uint64& variable);
// [12] getInt56(bsls::Types::Int64& variable);
// [12] getUint56(bsls::Types::Uint64& variable);
// [11] getInt48(bsls::Types::Int64& variable);
// [11] getUint48(bsls::Types::Uint64& variable);
// [10] getInt40(bsls::Types::Int64& variable);
// [10] getUint40(bsls::Types::Uint64& variable);
// [ 9] getInt32(int& variable);
// [ 9] getUint32(unsigned int& variable);
// [ 8] getInt24(int& variable);
// [ 8] getUint24(unsigned int& variable);
// [ 7] getInt16(short& variable);
// [ 7] getUint16(unsigned short& variable);
// [ 3] getInt8(char& variable);
// [ 6] getInt8(signed char& variable);
// [ 6] getUint8(char& variable);
// [ 6] getUint8(unsigned char& variable);
// [15] getFloat64(double& variable);
// [14] getFloat32(float& variable);
// [30] getString(bsl::string& variable);
// [23] getArrayInt64(bsls::Types::Int64 *variables, int numVariables);
// [23] getArrayUint64(bsls::Types::Uint64 *variables, int numVariables);
// [22] getArrayInt56(bsls::Types::Int64 *variables, int numVariables);
// [22] getArrayUint56(bsls::Types::Uint64 *variables, int numVariables);
// [21] getArrayInt48(bsls::Types::Int64 *variables, int numVariables);
// [21] getArrayUint48(bsls::Types::Uint64 *variables, int numVariables);
// [20] getArrayInt40(bsls::Types::Int64 *variables, int numVariables);
// [20] getArrayUint40(bsls::Types::Uint64 *variables, int numVariables);
// [19] getArrayInt32(int *variables, int numVariables);
// [19] getArrayUint32(unsigned int *variables, int numVariables);
// [18] getArrayInt24(int *variables, int numVariables);
// [18] getArrayUint24(unsigned int *variables, int numVariables);
// [17] getArrayInt16(short *variables, int numVariables);
// [17] getArrayUint16(unsigned short *variables, int numVariables);
// [16] getArrayInt8(char *variables, int numVariables);
// [16] getArrayInt8(signed char *variables, int numVariables);
// [16] getArrayUint8(char *variables, int numVariables);
// [16] getArrayUint8(unsigned char *variables, int numVariables);
// [25] getArrayFloat64(double *variables, int numVariables);
// [24] getArrayFloat32(float *variables, int numVariables);
// [ 3] void invalidate();
// [26] void reset();
// [28] void reset(const char *buffer, bsl::size_t numBytes);
// [28] void reset(const bslstl::StringRef& srcData);
// [27] setInputLimit(int limit);
// [ 3] setQuiet(int flag);
// [26] seek(bsl::size_t offset);
// [ 4] operator const void *() const;
// [ 4] bsl::size_t cursor() const;
// [27] int inputLimit() const;
// [ 4] bool isEmpty() const;
// [ 4] bool isValid() const;
// [ 3] bool isQuiet() const;
// [ 4] bsl::size_t length() const;
//
// [ 5] ostream& operator<<(ostream& stream, const TestInStream& obj);
// [31] TestInStream& operator>>(TestInStream&, TYPE& value);
// [32] BSLX_TESTINSTREAM_EXCEPTIONTEST_BEGIN(BSLX_TESTINSTREAM)
// [32] BSLX_TESTINSTREAM_EXCEPTIONTEST_END
// ----------------------------------------------------------------------------
// [33] USAGE TEST
// [ 1] BREATHING TEST
// [ 2] int g(Out* o, const char* spec);
// [27] Ensure every input method correctly modifies the input limit and throws
//      an exception when the input limit is exceeded.
// ----------------------------------------------------------------------------

// ============================================================================
//                    STANDARD BDE ASSERT TEST MACRO
// ----------------------------------------------------------------------------

namespace {

int testStatus = 0;

void aSsErT(int c, const char *s, int i)
{
    if (c) {
        cout << "Error " << __FILE__ << "(" << i << "): " << s
             << "    (failed)" << endl;
        if (0 <= testStatus && testStatus <= 100) ++testStatus;
    }
}

}  // close unnamed namespace

// ============================================================================
//                       STANDARD BDE TEST DRIVER MACROS
// ----------------------------------------------------------------------------

#define ASSERT       BSLS_BSLTESTUTIL_ASSERT
#define LOOP_ASSERT  BSLS_BSLTESTUTIL_LOOP_ASSERT
#define LOOP0_ASSERT BSLS_BSLTESTUTIL_LOOP0_ASSERT
#define LOOP1_ASSERT BSLS_BSLTESTUTIL_LOOP1_ASSERT
#define LOOP2_ASSERT BSLS_BSLTESTUTIL_LOOP2_ASSERT
#define LOOP3_ASSERT BSLS_BSLTESTUTIL_LOOP3_ASSERT
#define LOOP4_ASSERT BSLS_BSLTESTUTIL_LOOP4_ASSERT
#define LOOP5_ASSERT BSLS_BSLTESTUTIL_LOOP5_ASSERT
#define LOOP6_ASSERT BSLS_BSLTESTUTIL_LOOP6_ASSERT
#define ASSERTV      BSLS_BSLTESTUTIL_ASSERTV

#define Q   BSLS_BSLTESTUTIL_Q   // Quote identifier literally.
#define P   BSLS_BSLTESTUTIL_P   // Print identifier and value.
#define P_  BSLS_BSLTESTUTIL_P_  // P(X) without '\n'.
#define T_  BSLS_BSLTESTUTIL_T_  // Print a tab (w/o newline).
#define L_  BSLS_BSLTESTUTIL_L_  // current Line number

// ============================================================================
//                  NEGATIVE-TEST MACRO ABBREVIATIONS
// ----------------------------------------------------------------------------

#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR)
#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR)
#define ASSERT_PASS(EXPR)      BSLS_ASSERTTEST_ASSERT_PASS(EXPR)
#define ASSERT_FAIL(EXPR)      BSLS_ASSERTTEST_ASSERT_FAIL(EXPR)
#define ASSERT_OPT_PASS(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_PASS(EXPR)
#define ASSERT_OPT_FAIL(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_FAIL(EXPR)

// ============================================================================
//                      HELPER CLASSES AND FUNCTIONS
// ----------------------------------------------------------------------------

namespace BloombergLP {
namespace bslx {

void debugprint(const TestInStream& object)
{
    bsl::cout << object;
}

}  // close package namespace
}  // close enterprise namespace

// ============================================================================
//                   GLOBAL TYPEDEFS/CONSTANTS FOR TESTING
// ----------------------------------------------------------------------------

#define INT8_FL   "\xe0"
#define INT8_BYTE "e0"

typedef TestInStream Obj;
typedef TestOutStream Out;
typedef TypeCode FC;

const int VERSION_SELECTOR = 20131127;
const int SIZEOF_INT64   = 8;
const int SIZEOF_INT56   = 7;
const int SIZEOF_INT48   = 6;
const int SIZEOF_INT40   = 5;
const int SIZEOF_INT32   = 4;
const int SIZEOF_INT24   = 3;
const int SIZEOF_INT16   = 2;
const int SIZEOF_INT8    = 1;
const int SIZEOF_FLOAT64 = 8;
const int SIZEOF_FLOAT32 = 4;
const int SIZEOF_VERSION = 1;
const int VERSION        = 1;
const int SIZEOF_CODE    = 1;
const int VERSION_LEN    = SIZEOF_CODE + SIZEOF_VERSION;

const char           VA[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const signed char    VB[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const char           VC[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const unsigned char  VD[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const short          VE[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const unsigned short VF[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const int            VG[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const unsigned int   VH[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Int64
                     VI[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Uint64
                     VJ[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const float          VK[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const double         VL[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// The following constants are added to match the optimized methods for integer
// types, such as 'putInt24', 'putInt56', etc.
const int            VM[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const unsigned int   VN[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Int64
                     VO[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Uint64
                     VP[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Int64
                     VQ[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Uint64
                     VR[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Int64
                     VS[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const bsls::Types::Uint64
                     VT[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Data structure that contains data to test array input methods using the
// function 'testGetArray' (defined below).
struct ArrayTestTable {
    int         d_line;          // line number
    const char *d_spec;          // spec to create test stream
    int         d_isValid;       // expected final validity of object
    int         d_numArr;        // # arrays to read from stream
    int         d_arrLen[10];    // lengths of the arrays to read
    int         d_expArrLen[10]; // expected lengths of the arrays read
};

// Data structure that contains data to test scalar input methods using the
// function 'testGetScalar' (defined below).
template <class ElemType>
struct ScalarTestTable {
    int         d_line;          // line number
    const char *d_spec;          // spec to create test stream
    int         d_numVals;       // # of values to read from stream
    ElemType    d_exp[10];       // array of expected values read
};

struct InputLimitTestTable {
    int d_line;            // line number
    int d_inputLimit;      // input limit of stream
    int d_numInput;        // # of times an input method is invoked
    int d_willThrow;       // nonzero if exception is expected to be thrown
    int d_numSuccessInput; // # of times an input method is expected to succeed
};

// static int globalVerbose;
static int globalVeryVerbose;

// ============================================================================
//                    GENERATOR FUNCTION 'g' FOR TESTING
// ----------------------------------------------------------------------------
// The following function interprets the given 'spec' in order from left to
// right to configure a 'bslx::TestOutStream' object according to a custom
// language.  The language consists of letters in the ranges [A-T] and [a-t],
// and digits in the range [0-9].  A letter must be followed by one or more
// digits.  Each letter is associated with a unique output method to be invoked
// by the object.  The association is as follows:
//
// LETTER      OUTPUT METHOD      LETTER      OUTPUT METHOD
// ----------  ---------------    ----------  ------------------
//    A          putInt8             a          putArrayInt8
//    B          putInt8             b          putArrayInt8  (signed char)
//    C          putUint8            c          putArrayUint8
//    D          putUint8            d          putArrayUint8 (unsigned char)
//    E          putInt16            e          putArrayInt16
//    F          putUint16           f          putArrayUint16
//    G          putInt32            g          putArrayInt32
//    H          putUint32           h          putArrayUint32
//    I          putInt64            i          putArrayInt64
//    J          putUint64           j          putArrayUint64
//    K          putFloat32          k          putArrayFloat32
//    L          putFloat64          l          putArrayFloat64
//
//    M          putInt24            m          putArrayInt24
//    N          putUint24           n          putArrayUint24
//    O          putInt40            o          putArrayInt40
//    P          putUint40           p          putArrayUint40
//    Q          putInt48            q          putArrayInt48
//    R          putUint48           r          putArrayUint48
//    S          putInt56            s          putArrayInt56
//    T          putUint56           t          putArrayUint56
//
// Each letter is also case-insensitively associated with a predefined data
// array (see above definitions) having a name of the form VX, where X is in
// the range [A-T].
//
// For each uppercase letter (corresponding to a scalar output method), each
// digit N serves as an index into VX.  Thus, the spec 'G2' invokes 'putInt32'
// with the value VG[2].
//
// For each lowercase letter (corresponding to an array output method), each
// digit N indicates the first N elements of VX.  Thus, the spec 'l3' invokes
// 'putArrayFloat64' with the array VL, and length 3.
//
//
// LANGUAGE SPECIFICATION:
// -----------------------
//
// <SPEC>       ::= <EMPTY>
//                | <ITEM_LIST>
//
// <ITEM_LIST>  ::= <ITEM>
//                | <ITEM><ITEM_LIST>
//
// <ITEM>       ::= <ALPHA><DIGIT_LIST>
//
// <DIGIT_LIST> ::= <DIGIT>
//                | <DIGIT><DIGIT_LIST>
//
// <DIGIT>      ::= [0-9]
// <ALPHA>      ::= [A-Ta-t]
//
// <EMPTY>      ::=
//
// *Note - spaces may be inserted in any part of the language.
//
// Sample Spec  Description
// -----------  ---------------------------------------------------------------
// ""           Has no effect; leaves the object empty.
// "A0"         Externalize 'VA[0]' by calling 'putInt8(VA[0])'.
// "A123"       Externalize 'VA[1]', 'VA[2]', and 'VA[3]' by calling 'putInt8'
//              with 'VA[1]', 'VA[2]', and 'VA[3]' as arguments, respectively.
// "a2"         Externalize the first two elements of 'VA' by calling
//              'putArrayInt8(VA, 2)'.
// "a25"        Externalize the first two elements of 'VA' by calling
//              'putArrayInt8(VA, 2)', then the first five elements of 'VA' by
//              calling 'putArrayInt8(VA, 5)'.
// "A01 B234 E5 f6 g23 H1"
//              Externalize 'VA[0]' and 'VA[1]' with 'putInt8'; 'VB[2]',
//              'VB[3]', and 'VB[4]' with 'putUint8'; 'VE[5]' with 'putInt16';
//              the first six elements of 'VF' with 'putArrayUint16(VF, 6)';
//              the first two elements of 'VG' with 'putArrayInt32(VG, 2)'; the
//              first three elements of 'VG' with 'putArrayInt32(VG, 3)', and
//              'VH[1]' with 'putUint32'
//
// ----------------------------------------------------------------------------

int g(Out *o, const char *spec) {
    // int verbose = globalVerbose;
    int veryVerbose = globalVeryVerbose;

    // read spec from left to right
    for (int i = 0; spec[i]; ++i) {
        if (spec[i] == ' ' || spec[i] == '\t') continue; // Skip spaces

        if (('A' <= spec[i] && spec[i] <= 'T') ||
           ('a' <= spec[i] && spec[i] <= 't' ) ) {
            // found a letter

            bool haveDigit = false; // set to 'true' if digits found following
                                    // letter

            for (int j = i + 1; spec[j]; ++j) {
                if ('0' <= spec[j] && spec[j] <= '9') {
                    // found a digit

                    haveDigit = true;
                    int n = spec[j] - '0';

                    switch (spec[i]) {
                      case 'A':    o->putInt8(VA[n]);            break;
                      case 'B':    o->putInt8(VB[n]);            break;
                      case 'C':    o->putUint8(VC[n]);           break;
                      case 'D':    o->putUint8(VD[n]);           break;
                      case 'E':    o->putInt16(VE[n]);           break;
                      case 'F':    o->putUint16(VF[n]);          break;
                      case 'G':    o->putInt32(VG[n]);           break;
                      case 'H':    o->putUint32(VH[n]);          break;
                      case 'I':    o->putInt64(VI[n]);           break;
                      case 'J':    o->putUint64(VJ[n]);          break;
                      case 'K':    o->putFloat32(VK[n]);         break;
                      case 'L':    o->putFloat64(VL[n]);         break;
                      case 'M':    o->putInt24(VM[n]);           break;
                      case 'N':    o->putUint24(VN[n]);          break;
                      case 'O':    o->putInt40(VO[n]);           break;
                      case 'P':    o->putUint40(VP[n]);          break;
                      case 'Q':    o->putInt48(VQ[n]);           break;
                      case 'R':    o->putUint48(VR[n]);          break;
                      case 'S':    o->putInt56(VS[n]);           break;
                      case 'T':    o->putUint56(VT[n]);          break;
                      case 'a':    o->putArrayInt8(VA, n);       break;
                      case 'b':    o->putArrayInt8(VB, n);       break;
                      case 'c':    o->putArrayUint8(VC, n);      break;
                      case 'd':    o->putArrayUint8(VD, n);      break;
                      case 'e':    o->putArrayInt16(VE, n);      break;
                      case 'f':    o->putArrayUint16(VF, n);     break;
                      case 'g':    o->putArrayInt32(VG, n);      break;
                      case 'h':    o->putArrayUint32(VH, n);     break;
                      case 'i':    o->putArrayInt64(VI, n);      break;
                      case 'j':    o->putArrayUint64(VJ, n);     break;
                      case 'k':    o->putArrayFloat32(VK, n);    break;
                      case 'l':    o->putArrayFloat64(VL, n);    break;
                      case 'm':    o->putArrayInt24(VM, n);      break;
                      case 'n':    o->putArrayUint24(VN, n);     break;
                      case 'o':    o->putArrayInt40(VO, n);      break;
                      case 'p':    o->putArrayUint40(VP, n);     break;
                      case 'q':    o->putArrayInt48(VQ, n);      break;
                      case 'r':    o->putArrayUint48(VR, n);     break;
                      case 's':    o->putArrayInt56(VS, n);      break;
                      case 't':    o->putArrayUint56(VT, n);     break;
                    }
                } else if (spec[j] == ' ' || spec[j] == '\t') {
                    ; // skip spaces
                } else {
                    // spec[j] is not in [0-9] and is not a space.  Break.
                    // assign 'i' to j - 1 b/c 'i' will be incremented later.
                    i = j - 1;
                    break;
                }

                if ('\0' == spec[j + 1]) {
                    // next char is null, assign 'i' and break.
                    i = j;
                    break;
                }
            }

            if (!haveDigit) {
                if (veryVerbose)
                    cout << "*** missing digit after letter ***" << endl;
                return 0;     // discontinue processing this spec.    // RETURN
            }
        } else {
            if (veryVerbose)
                cout << "*** bad character ('" << spec[i] << "') in spec \""
                     << spec << "\" at position " << i << " ***" << endl;
            return 0;         // discontinue processing this spec.    // RETURN
        }
    }
    return 1;
}

// ============================================================================
//                    FUNCTION 'testGetArray' FOR TESTING
// ----------------------------------------------------------------------------
// The function 'testGetArray' is a generic, parameterized function to test
// array input methods of various data types.  The function accepts an array of
// vectors having the structure defined by 'ArrayTestTable' (see above) as its
// test data.  It iterates over the vectors in the array and performs an
// independent test for each vector.  In each test, it first generates a test
// stream using the generator function 'g' with spec 'd_spec', then attempts to
// read 'd_numArr' number of arrays from the stream with consecutive array
// input method calls.  For the Nth array input method call, it attempts to
// read an array having a length equal to the value of the Nth element of
// 'd_arrLen' array.  For example, if N is 5 and 'getArrayInt8' is being
// tested, then 'getArrayInt8(input_array, d_arrLen[5])' will be called (where
// 'input_array' is an array that will contain the values read from the stream
// if the call returns successfully).  The resulting length of the input array
// is verified against the value of the Nth element of 'd_expArrLen' array.
// The value of each element in the input array is also verified against the
// value of the respective element in the 'origVal' array.  If a test stream
// contains all valid data, then the stream is verified to be empty and valid
// after all input operations.  If a test stream is intentionally configured
// with invalid data, then after the attempt to read the invalid data, the
// element values of the input array is verified to be unchanged, and that the
// stream becomes invalid.  Note that error messages from the stream object is
// displayed only in "veryVerbose" mode.
// ----------------------------------------------------------------------------

template <class ElemType, class FuncPtr>
void testGetArray(const ArrayTestTable *data,
                  int                   numTest,
                  const ElemType       *origVal,
                  FuncPtr               getArrayFunc)
    // Iterate over the vectors in the specified 'data' by the specified
    // 'numTest' times.  Generate a test stream in each iteration, invoke the
    // array input method pointed to by the specified 'getArrayFunc' member
    // pointer, and then verify the result by comparing the values in the
    // extracted array to the values in the specified 'origVal' array.
    // Also verify defensive checks are triggered for invalid values.
{
    // int verbose = globalVerbose;
    int veryVerbose = globalVeryVerbose;

    for (int i = 0; i < numTest; ++i)
    {
        const char *spec = data[i].d_spec;
        const int line = data[i].d_line;
        if (veryVerbose) {
            cout << "\tSPEC : \"" <<  spec << '"' << endl;
        }

        Out o(VERSION_SELECTOR);
        int res = g(&o, spec);
        LOOP2_ASSERT(line, i, 1 == res);
        Obj mX(o.data(), o.length());  const Obj& X = mX;
        mX.setQuiet(!veryVerbose);

        if (res) {
            const int expObjValidity = data[i].d_isValid;
            const int numArr = data[i].d_numArr;

            // attempt to read each array in the stream
            for (int j = 0; j < numArr; ++j) {
                const int SIZE = 100;                 // temporary array size
                ElemType arr[SIZE];                   // array of read values
                const ElemType VX = (ElemType) 0xFF;  // "uninitialized" value
                int k;
                for (k = 0; k < SIZE; ++k) arr[k] = VX;

                const int arrLen = data[i].d_arrLen[j];

                // Read the values and verify the return value.

                ASSERT(&mX == &(mX.*getArrayFunc)(arr, arrLen));

                const int expArrLen = data[i].d_expArrLen[j];

                // verify read values
                for (k = 0; k < expArrLen; ++k)
                    LOOP4_ASSERT(line, i, j, k, origVal[k] == arr[k]);
                // Check for overrun
                for (k = expArrLen; k < SIZE - expArrLen; ++k)
                    LOOP4_ASSERT(line, i, j, k, VX == arr[k]);
            }
            LOOP2_ASSERT(line, i, !!X == !!expObjValidity);
            if (expObjValidity) {
                LOOP2_ASSERT(line, i, X.isEmpty());
                LOOP2_ASSERT(line,
                             i,
                             X.cursor() == X.length());
            }
        }
    }

    {
        // Verify method has no effect if the stream is invalid.

        const int SIZE = 3;                   // array size
        ElemType data[SIZE] = { 1, 1, 1 };    // array of original values
        ElemType arr[SIZE]  = { 0, 0, 0 };    // array of read values

        Obj        mX(reinterpret_cast<const char *>(data), sizeof data);
        const Obj& X = mX;

        mX.setQuiet(true);
        mX.invalidate();
        (mX.*getArrayFunc)(arr, SIZE);
        ASSERT(0 == arr[0] && 0 == arr[1] && 0 == arr[2]);
        ASSERT(0 == X.cursor());
    }

    {
        // negative test
        bsls::AssertTestHandlerGuard guard;

        const int SIZE = 5;                   // temporary array size
        ElemType arr[SIZE];                   // array of read values
        {
            Obj mX(reinterpret_cast<const char *>(arr), sizeof arr);
            mX.setQuiet(true);
            ASSERT_FAIL((mX.*getArrayFunc)(0, 0));
        }
        {
            Obj mX(reinterpret_cast<const char *>(arr), sizeof arr);
            mX.setQuiet(true);
            ASSERT_FAIL((mX.*getArrayFunc)(arr, -1));
        }
        {
            Obj mX(reinterpret_cast<const char *>(arr), sizeof arr);
            mX.setQuiet(true);
            ASSERT_PASS((mX.*getArrayFunc)(arr, 0));
        }
        {
            Obj mX(reinterpret_cast<const char *>(arr), sizeof arr);
            mX.setQuiet(true);
            ASSERT_PASS((mX.*getArrayFunc)(arr, 1));
        }
    }

}

// ============================================================================
//                    FUNCTION 'testGetScalar' FOR TESTING
// ----------------------------------------------------------------------------
// The function 'testGetScalar' is a generic, parameterized function to test
// scalar input methods of various data types.  The function accepts an array
// of vectors having the structure defined by 'ScalarTestTable' (see above) as
// its test data.  It iterates over the vectors in the array and performs an
// independent test for each vector.  In each test, it first generates a test
// stream using the generator function 'g' with spec 'd_spec', then attempts to
// read 'd_numVals' number of scalar values from the stream with consecutive
// input method calls.  For the Nth input method call, the value read is
// verified against the value of the Nth element of array 'd_exp'.  For
// example, if N is 5 and 'getInt8' is being tested, then 'getInt8(val)' is
// called, and the resulting value of 'val' is verified against 'd_exp[5]'.  If
// a test stream contains all valid data, then the stream is verified to be
// empty and valid after all input operations.  If a test stream is
// intentionally configured with invalid data, then after the attempt to read
// the invalid data, the value of the input variable is verified to be
// unchanged, and that the stream becomes invalid.  Note that error messages
// from the stream object is displayed only in "veryVerbose" mode.
// ----------------------------------------------------------------------------

template <class ElemType, class FuncPtr>
void testGetScalar(const ScalarTestTable<ElemType> *data,
                   int                              numTest,
                   FuncPtr                          getFunc)
    // Iterate over the vectors in the specified 'data' by the specified
    // 'numTest' times.  Generate a test stream in each iteration, invoke the
    // input method pointed to by the specified 'getFunc' member pointer, and
    // then verify the result by comparing the extracted values to the values
    // specified in the test vector.
{
    // int verbose = globalVerbose;
    int veryVerbose = globalVeryVerbose;

    for (int i = 0; i < numTest; ++i)
    {
        const char *spec = data[i].d_spec;
        const int line = data[i].d_line;
        if (veryVerbose) {
            cout << "\tSPEC : \"" <<  spec << '"' << endl;
        }
        Out o(VERSION_SELECTOR);
        int res = g(&o, spec);
        LOOP2_ASSERT(line, i, 1 == res);
        Obj mX(o.data(), o.length());  const Obj& X = mX;
        mX.setQuiet(!veryVerbose);

        if (res) {
            const int numVals = data[i].d_numVals;
            int numRead = 0;

            // attempt to read every value in stream
            for (int j = 0; j < numVals; ++j) {
                const ElemType VX = (ElemType) 0xFF;  // "uninitialized" value
                ElemType val = VX;                    // initialize to VX

                // Read the value and verify the return value.

                ASSERT(&mX == &(mX.*getFunc)(val));

                const ElemType expVal = data[i].d_exp[j];
                if (expVal != 0) {       // valid value read
                    LOOP3_ASSERT(line, i, j, expVal == val);
                    ++numRead;
                } else {                 // invalid value read
                    LOOP3_ASSERT(line, i, j, VX == val);
                    LOOP3_ASSERT(line, i, j, !X);
                }
            }

            if (numVals == numRead) {
                LOOP2_ASSERT(line, i, !!X);
                LOOP2_ASSERT(line, i, X.isEmpty());
                LOOP2_ASSERT(line,
                             i,
                             X.cursor() == X.length());
            }
        }
    }

    {
        // Verify method has no effect if the stream is invalid.

        ElemType data = 1;
        ElemType val = 0;

        Obj        mX(reinterpret_cast<const char *>(&data), sizeof data);
        const Obj& X = mX;

        mX.setQuiet(true);
        mX.invalidate();
        (mX.*getFunc)(val);
        ASSERT(0 == val);
        ASSERT(0 == X.cursor());
    }
}

// ============================================================================
//                FUNCTION 'testGetArrayInputLimit' FOR TESTING
// ----------------------------------------------------------------------------
// The function 'testGetArrayInputLimit' is a generic, parameterized function
// to test the behavior of array input methods with varying stream input limit
// values.  The function accepts as its test data an array of vectors having
// the structure defined by 'InputLimitTestTable' (see above) and performs an
// independent test for each vector.  In each test, a test input stream is
// created and initialized with the output of the generator function 'g' using
// 'spec'.  The stream's input limit is set to 'd_inputLimit', and the stream's
// input method referred to by the 'getFunc' function pointer is invoked
// repeatedly within a loop up to 'd_numInput' times.  Depending on the
// stream's input limit, the input method may throw an exception and exit the
// 'loop'.  When the loop exits, the number of times that the input method was
// executed is verified against 'd_numSuccessInput', and the flag that
// indicates whether an exception was thrown is verified against 'd_willThrow'.
// The input method is again executed 'd_numInput' times to ensure that after a
// non-negative input limit has been exceeded and an exception has been thrown,
// subsequent input method invocations do not throw unless the input limit is
// updated with a non-negative value.
// ----------------------------------------------------------------------------

template <class ElemType, class FuncPtr>
void testGetArrayInputLimit(const InputLimitTestTable *data,
                            int                        numData,
                            const char                *spec,
                            int                        numArrayElements,
                            FuncPtr                    getFunc,
                            TypeCode::Enum            dataType)
    // Iterate over the specified 'data' test vectors 'numData' times.  In each
    // iteration, create a test input stream object initialized with the output
    // of the generator function 'g' using the specified 'spec'.  Invoke some
    // number of times (specified in the test vector) the array input method
    // referred to by the specified 'getFunc' member function pointer to input
    // an array containing the specified 'numArrayElements'.  Verify that the
    // number of times the input method was invoked is equal to the expected
    // value specified in the test vector, and that an exception was thrown and
    // caught when expected.  If an exception was thrown, verified that the
    // exception object contains the specified 'dataType'.
{
#ifdef BDE_BUILD_TARGET_EXC
    // int verbose = globalVerbose;
    int veryVerbose = globalVeryVerbose;

    const int SIZE = 100;
    ElemType array[SIZE];

    Out o(VERSION_SELECTOR);
    int res = g(&o, spec);    ASSERT(res);

    {
        for (int i = 0; i < numData; ++i) {
            const int LINE     = data[i].d_line;
            const int LIMIT    = data[i].d_inputLimit;
            const int NUM_IN   = data[i].d_numInput;
            const int THROWN   = data[i].d_willThrow;
            const int NUM_SUCC = data[i].d_numSuccessInput;
            LOOP2_ASSERT(LINE, i, NUM_IN <= SIZE);

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            mX.setInputLimit(LIMIT);

            int numInput;
            int thrown = 0;
            try {
                for (numInput = 0; numInput < NUM_IN; ++numInput) {
                    (mX.*getFunc)(array, numArrayElements);
                }
            }
            catch (TestInStreamException& e) {
                thrown = 1;
                if (veryVerbose) cout << "\t*** Caught Exception : type = "
                                      << e.dataType() << " ***" << endl;
                LOOP3_ASSERT(LINE, i, numInput, dataType == e.dataType());
            }
            if (veryVerbose) {
                cout << '\t';
                P_(numInput);
                P(X.inputLimit());
            }
            LOOP2_ASSERT(LINE, i, NUM_SUCC == numInput);
            LOOP2_ASSERT(LINE, i,   THROWN == thrown);
            LOOP2_ASSERT(LINE, i, X);

            // ensure that once input limit is exceeded and exception has
            // been thrown, then no exception will be thrown again
            if (X.inputLimit() < 0) {
                mX.seek(0);
                try {
                    for (numInput = 0; numInput < NUM_IN; ++numInput) {
                        (mX.*getFunc)(array, numArrayElements);
                    }
                }
                catch (TestInStreamException& e) {
                    LOOP3_ASSERT(LINE, i, numInput,
                                 0 && "\t*** Unexpected exception ***\n");
                    if (veryVerbose) {
                        cout << "\ttype = " << e.dataType() << endl;
                    }
                }
            }
        }
    }

#endif
}

// ============================================================================
//               FUNCTION 'testGetScalarInputLimit' FOR TESTING
// ----------------------------------------------------------------------------
// The function 'testGetScalarInputLimit' is a generic, parameterized function
// to test the behavior of scalar input methods with varying stream input limit
// values.  The function accepts as its test data an array of vectors having
// the structure defined by 'InputLimitTestTable' (see above) and performs an
// independent test for each vector.  In each test, a test input stream is
// created and initialized with the output of the generator function 'g' using
// 'spec'.  The stream's input limit is set to 'd_inputLimit', and the stream's
// input method referred to by the 'getFunc' function pointer is invoked
// repeatedly within a loop up to 'd_numInput' times.  Depending on the
// stream's input limit, the input method may throw an exception and exit the
// 'loop'.  When the loop exits, the number of times that the input method was
// executed is verified against 'd_numSuccessInput', and the flag that
// indicates whether an exception was thrown is verified against 'd_willThrow'.
// The input method is again executed 'd_numInput' times to ensure that after a
// non-negative input limit has been exceeded and an exception has been thrown,
// subsequent input method invocations do not throw unless the input limit is
// updated with a non-negative value.
// ----------------------------------------------------------------------------

template <class ElemType>
void testGetScalarInputLimit(const InputLimitTestTable        *data,
                             int                              numData,
                             const char                      *spec,
                             Obj& (Obj::*getFunc)(ElemType&),
                             TypeCode::Enum                  dataType)
    // Iterate over the specified 'data' test vectors 'numData' times.  In each
    // iteration, create a test input stream object initialized with the output
    // of the generator function 'g' using the specified 'spec'.  Invoke some
    // number of times (specified in the test vector) the scalar input method
    // referred to by the specified 'getFunc' member function pointer.  Verify
    // that the number of times the input method was invoked is equal to the
    // expected value specified in the test vector, and that an exception was
    // thrown and caught when expected.  If an exception was thrown, verified
    // that the exception object contains the specified 'dataType'.
{
#ifdef BDE_BUILD_TARGET_EXC
    // int verbose = globalVerbose;
    int veryVerbose = globalVeryVerbose;

    ElemType value;

    Out o(VERSION_SELECTOR);
    int res = g(&o, spec);    ASSERT(res);

    {
        for (int i = 0; i < numData; ++i) {
            const int LINE    = data[i].d_line;
            const int LIMIT   = data[i].d_inputLimit;
            const int NUM_IN  = data[i].d_numInput;
            const int THROWN   = data[i].d_willThrow;
            const int NUM_SUCC = data[i].d_numSuccessInput;

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            mX.setInputLimit(LIMIT);

            int numInput;
            int thrown = 0;
            try {
                for (numInput = 0; numInput < NUM_IN; ++numInput) {
                    (mX.*getFunc)(value);
                }
            }
            catch (TestInStreamException& e) {
                thrown = 1;
                if (veryVerbose) cout << "\t*** Caught Exception : type = "
                                      << e.dataType() << " ***" << endl;
                LOOP3_ASSERT(LINE, i, numInput, dataType == e.dataType());
            }
            if (veryVerbose) {
                cout << '\t';
                P_(numInput);
                P(X.inputLimit());
            }
            LOOP2_ASSERT(LINE, i, NUM_SUCC == numInput);
            LOOP2_ASSERT(LINE, i,   THROWN == thrown);
            LOOP2_ASSERT(LINE, i, X);

            // ensure that once input limit is exceeded and exception has
            // been thrown, then no exception will be thrown again
            if (X.inputLimit() < 0) {
                mX.seek(0);
                try {
                    for (numInput = 0; numInput < NUM_IN; ++numInput) {
                        (mX.*getFunc)(value);
                    }
                }
                catch (TestInStreamException& e) {
                    LOOP3_ASSERT(LINE, i, numInput,
                                 0 && "\t*** Unexpected exception ***\n");
                    if (veryVerbose) {
                        cout << "\ttype = " << e.dataType() << endl;
                    }
                }
            }
        }
    }

#endif
}

// ============================================================================
//               STRUCT 'ForEachIn<LIST, N>' FOR TESTING
// ----------------------------------------------------------------------------
template <class LIST, int N = LIST::LENGTH>
struct ForEachIn {
    // The struct 'ForEachIn' is a generic, parameterized structure that
    // implements meta-function 'testInputLimit'.  The function
    // recursively instantiates 'ForEachIn<LIST, N-1>' unless N=0.
    // For the i-th instantiation, the function calls the 'test' method of
    // the i-th item of the 'LIST'.

    static void testInputLimit(const InputLimitTestTable *data,
                               int                        numData,
                               const char                *specs[])
        // The function extracts N-th element from the 'LIST' and
        // invokes its static method 'test' with the specified 'data',
        // 'numData', (N-1)-th item of the specified 'specs' array.  After that
        // the function instantiates struct 'ForEachIn<LIST, N-1>' and
        // invokes its static method 'testInputLimit'.  The process
        // recursively continues unless N=0, in this case partial
        // specialization for 'ForEachIn<LIST, 0>' is instantiated (see
        // below) and recursion is stopped.
    {
        ASSERT(specs[N - 1]);

        typedef typename bslmf::TypeListTypeOf<N, LIST>::Type Item;
        Item::test(data, numData, specs[N - 1]);

        ForEachIn<LIST, N - 1>::testInputLimit(data, numData, specs);
    }
};

// ============================================================================
//               STRUCT 'ForEachIn<LIST, 0>' FOR TESTING
// ----------------------------------------------------------------------------
template <class LIST>
struct ForEachIn<LIST, 0> {
    // Partial specialization of struct 'ForEachIn' for N = 0
    static void testInputLimit(const InputLimitTestTable *,
                               int,
                               const char *[])
        // Empty implementation
    {
    }
};

// ============================================================================
//               STRUCT 'GetScalar' FOR TESTING
// ----------------------------------------------------------------------------
template <class ElemType,
          Obj& (Obj::*getFunc)(ElemType&),
          TypeCode::Enum tc>
struct GetScalar {
    // The struct 'GetScalar' is a generic, parameterized structure that
    // helps to store an address of 'TestInStream' access function for
    // the specified type 'ElemType' and corresponding type code type
    // 'tc'.  The struct serves as an item of a type list in INPUT
    // LIMIT EXCEPTION TEST (case 27).
    static void test(const InputLimitTestTable *data,
                     int                        numData,
                     const char                *spec) {
        // invokes 'testGetScalarInputLimit' template function with the
        // specified 'data', 'numData', 'spec' function parameters and
        // 'getFunc', 'tc' template parameters.
        testGetScalarInputLimit<ElemType>(data, numData, spec, getFunc, tc);
    }
};

// ============================================================================
//               STRUCT 'GetArray' FOR TESTING
// ----------------------------------------------------------------------------
template <class ElemType,
          Obj& (Obj::*getFunc)(ElemType*, int),
          TypeCode::Enum tc,
          int numArrayElements>
struct GetArray {
    // The struct 'GetArray' is a generic, parameterized structure that
    // helps to store an address of 'TestInStream' access function for
    // the specified type 'ElemType', corresponding type code type
    // 'tc' and 'numArrayElements' value.  The struct serves as an item
    // of a type list in INPUT LIMIT EXCEPTION TEST (case 27).
    static void test(const InputLimitTestTable *data,
                     int                        numData,
                     const char                *spec) {
        // invokes 'testGetArrayInputLimit' template function with the
        // specified 'data', 'numData', 'spec' function parameters and
        // 'numArrayElements', 'getFunc', 'tc' template parameters.
        testGetArrayInputLimit<ElemType>(
            data,
            numData,
            spec,
            numArrayElements,
            getFunc,
            tc);
    }
};

// ============================================================================
//                                 USAGE EXAMPLE
// ----------------------------------------------------------------------------

///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Unexternalization
///- - - - - - - - - - - - - - - - -
// Suppose we wish to implement a (deliberately simple) 'MyPerson' class as a
// value-semantic object that supports BDEX externalization and
// unexternalization.  In addition to whatever data and methods that we choose
// to put into our design, we must supply three methods having specific names
// and signatures in order to comply with the BDEX protocol: a class method
// 'maxSupportedBdexVersion', an accessor (i.e., a 'const' method)
// 'bdexStreamOut', and a manipulator (i.e., a non-'const' method)
// 'bdexStreamIn'.  This example shows how to implement those three methods.
//
// In this example we will not worry overly about "good design" of the
// 'MyPerson' component, and we will declare but not implement illustrative
// methods and free operators, except for the three required BDEX methods,
// which are implemented in full.  In particular, we will not make explicit use
// of 'bslma' allocators; a more complete design would do so:
//
// First, we implement 'MyPerson':
//..
    class MyPerson {
        bsl::string d_firstName;
        bsl::string d_lastName;
        int         d_age;

        friend bool operator==(const MyPerson&, const MyPerson&);

      public:
        // CLASS METHODS
        static int maxSupportedBdexVersion(int versionSelector);
            // Return the maximum valid BDEX format version, as indicated by
            // the specified 'versionSelector', to be passed to the
            // 'bdexStreamOut' method.  Note that it is highly recommended that
            // 'versionSelector' be formatted as "YYYYMMDD", a date
            // representation.  Also note that 'versionSelector' should be a
            // *compile*-time-chosen value that selects a format version
            // supported by both externalizer and unexternalizer.  See the
            // 'bslx' package-level documentation for more information on BDEX
            // streaming of value-semantic types and containers.

        // CREATORS
        MyPerson();
            // Create a default person.

        MyPerson(const char *firstName, const char *lastName, int age);
            // Create a person having the specified 'firstName', 'lastName',
            // and 'age'.

        MyPerson(const MyPerson& original);
            // Create a person having the value of the specified 'original'
            // person.

        ~MyPerson();
            // Destroy this object.

        // MANIPULATORS
        MyPerson& operator=(const MyPerson& rhs);
            // Assign to this person the value of the specified 'rhs' person,
            // and return a reference to this person.

        template <class STREAM>
        STREAM& bdexStreamIn(STREAM& stream, int version);
            // Assign to this object the value read from the specified input
            // 'stream' using the specified 'version' format, and return a
            // reference to 'stream'.  If 'stream' is initially invalid, this
            // operation has no effect.  If 'version' is not supported, this
            // object is unaltered and 'stream' is invalidated, but otherwise
            // unmodified.  If 'version' is supported but 'stream' becomes
            // invalid during this operation, this object has an undefined, but
            // valid, state.  Note that no version is read from 'stream'.  See
            // the 'bslx' package-level documentation for more information on
            // BDEX streaming of value-semantic types and containers.

        //...

        // ACCESSORS
        const bsl::string& firstName() const;
            // Return the first name of this person.

        const bsl::string& lastName() const;
            // Return the last name of this person.

        int age() const;
            // Return the age of this person.

        template <class STREAM>
        STREAM& bdexStreamOut(STREAM& stream, int version) const;
            // Write the value of this object, using the specified 'version'
            // format, to the specified output 'stream', and return a reference
            // to 'stream'.  If 'stream' is initially invalid, this operation
            // has no effect.  If 'version' is not supported, 'stream' is
            // invalidated, but otherwise unmodified.  Note that 'version' is
            // not written to 'stream'.  See the 'bslx' package-level
            // documentation for more information on BDEX streaming of
            // value-semantic types and containers.

        //...

    };

    // FREE OPERATORS
    bool operator==(const MyPerson& lhs, const MyPerson& rhs);
        // Return 'true' if the specified 'lhs' and 'rhs' person objects have
        // the same value and, 'false' otherwise.  Two person objects have the
        // same value if they have the same first name, last name, and age.

    bool operator!=(const MyPerson& lhs, const MyPerson& rhs);
        // Return 'true' if the specified 'lhs' and 'rhs' person objects do not
        // have the same value, and 'false' otherwise.  Two person objects
        // differ in value if they differ in first name, last name, or age.

    bsl::ostream& operator<<(bsl::ostream& stream, const MyPerson& person);
        // Write the specified 'person' value to the specified output 'stream'
        // in some reasonable format, and return a reference to 'stream'.

    // ========================================================================
    //                  INLINE FUNCTION DEFINITIONS
    // ========================================================================

    // CLASS METHODS
    inline
    int MyPerson::maxSupportedBdexVersion(int /* versionSelector */) {
        return 1;
    }

    // CREATORS
    inline
    MyPerson::MyPerson()
    : d_firstName("")
    , d_lastName("")
    , d_age(0)
    {
    }

    inline
    MyPerson::MyPerson(const char *firstName, const char *lastName, int age)
    : d_firstName(firstName)
    , d_lastName(lastName)
    , d_age(age)
    {
    }

    inline
    MyPerson::~MyPerson()
    {
    }

    template <class STREAM>
    STREAM& MyPerson::bdexStreamIn(STREAM& stream, int version)
    {
        if (stream) {
            switch (version) {  // switch on the 'bslx' version
              case 1: {
                stream.getString(d_firstName);
                if (!stream) {
                    d_firstName = "stream error";  // *might* be corrupted;
                                                   //  value for testing
                    return stream;                                    // RETURN
                }
                stream.getString(d_lastName);
                if (!stream) {
                    d_lastName = "stream error";  // *might* be corrupted;
                                                  //  value for testing
                    return stream;                                    // RETURN
                }
                stream.getInt32(d_age);
                if (!stream) {
                    d_age = 999;     // *might* be corrupted; value for testing
                    return stream;                                    // RETURN
                }
              } break;
              default: {
                stream.invalidate();
              }
            }
        }
        return stream;
    }

    // ACCESSORS
    template <class STREAM>
    STREAM& MyPerson::bdexStreamOut(STREAM& stream, int version) const
    {
        switch (version) {
          case 1: {
            stream.putString(d_firstName);
            stream.putString(d_lastName);
            stream.putInt32(d_age);
          } break;
          default: {
            stream.invalidate();
          } break;
        }
        return stream;
    }
//..

   // ACCESSORS
   const bsl::string& MyPerson::firstName() const
   {
       return d_firstName;
   }

   const bsl::string& MyPerson::lastName() const
   {
       return d_lastName;
   }

   int MyPerson::age() const
   {
       return d_age;
   }

   // FREE OPERATORS
   inline
   bool operator==(const MyPerson& lhs, const MyPerson& rhs)
   {
       return lhs.d_firstName == rhs.d_firstName &&
              lhs.d_lastName  == rhs.d_lastName  &&
              lhs.d_age       == rhs.d_age;
   }

   inline
   bool operator!=(const MyPerson& lhs, const MyPerson& rhs)
   {
       return !(lhs == rhs);
   }

// ============================================================================
//                                MAIN PROGRAM
// ----------------------------------------------------------------------------

int main(int argc, char *argv[]) {
    int test = argc > 1 ? atoi(argv[1]) : 0;
    int verbose = argc > 2;
    int veryVerbose = globalVeryVerbose = argc > 3;
    int veryVeryVerbose = argc > 4;

    cout << "TEST " << __FILE__ << " CASE " << test << endl;

    switch (test) { case 0:
      case 33: {
        // --------------------------------------------------------------------
        // USAGE EXAMPLE
        //
        // Concerns:
        //: 1 The usage example provided in the component header file must
        //:   compile, link, and run as shown.
        //
        // Plan:
        //: 1 Incorporate usage example from header into test driver, replace
        //:   leading comment characters with spaces, replace 'assert' with
        //:   'ASSERT', and insert 'if (veryVerbose)' before all output
        //:   operations.  (C-1)
        //
        // Testing:
        //   USAGE EXAMPLE
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "USAGE EXAMPLE" << endl
                                  << "=============" << endl;

// Then, we can exercise the new 'MyPerson' value-semantic class by
// externalizing and reconstituting an object.  First, create a 'MyPerson'
// 'janeSmith' and a 'bslx::TestOutStream' 'outStream':
//..
    MyPerson janeSmith("Jane", "Smith", 42);
    bslx::TestOutStream outStream(20131127);
    const int VERSION = 1;
    outStream.putVersion(VERSION);
    janeSmith.bdexStreamOut(outStream, VERSION);
    ASSERT(outStream.isValid());
//..
// Next, create a 'MyPerson' 'janeCopy' initialized to the default value, and
// assert that 'janeCopy' is different from 'janeSmith':
//..
    MyPerson janeCopy;
    ASSERT(janeCopy != janeSmith);
//..
// Then, create a 'bslx::TestInStream' 'inStream' initialized with the buffer
// from the 'bslx::TestOutStream' object 'outStream' and unexternalize this
// data into 'janeCopy':
//..
    bslx::TestInStream inStream(outStream.data(), outStream.length());
    int version;
    inStream.getVersion(version);
    janeCopy.bdexStreamIn(inStream, version);
    ASSERT(inStream.isValid());
//..
// Finally, 'assert' the obtained values are as expected and display the
// results to 'bsl::stdout':
//..
    ASSERT(version  == VERSION);
    ASSERT(janeCopy == janeSmith);

    if (veryVerbose) {
    if (janeCopy == janeSmith) {
        bsl::cout << "Successfully serialized and de-serialized Jane Smith:"
                  << "\n\tFirstName: " << janeCopy.firstName()
                  << "\n\tLastName : " << janeCopy.lastName()
                  << "\n\tAge      : " << janeCopy.age() << bsl::endl;
    }
    else {
        bsl::cout << "Serialization unsuccessful.  'janeCopy' holds:"
                  << "\n\tFirstName: " << janeCopy.firstName()
                  << "\n\tLastName : " << janeCopy.lastName()
                  << "\n\tAge      : " << janeCopy.age() << bsl::endl;
    }
    } // if (veryVerbose)
//..

      } break;
      case 32: {
        // --------------------------------------------------------------------
        // EXCEPTION MACROS
        //   Verify the exception macros work as expected.
        //
        // Concerns:
        //: 1 The macros will iterate until the required number of inputs
        //:   are performed.
        //
        // Plan:
        //: 1 Populate a buffer by using a 'TestOutStream' to 'putInt32' a
        //:   specified number of times 'N' (for some range of 'N').
        //:
        //: 2 Within the macros, attempt to 'getInt32' 'N' times and, before
        //:   every 'getInt32' invocation, increment the total number of
        //:   input operations performed.
        //:
        //: 3 Verify T == N + N * (N + 1) / 2 (or T == N * (N + 3) / 2), which
        //:   corresponds to a successful input of all data and all the
        //:   required "failed" reads due to exceptions.  (C-1)
        //
        // Testing:
        //   BSLX_TESTINSTREAM_EXCEPTIONTEST_BEGIN(BSLX_TESTINSTREAM)
        //   BSLX_TESTINSTREAM_EXCEPTIONTEST_END
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "EXCEPTION MACROS" << endl
                          << "================" << endl;

        for (int requiredInputs = 1; requiredInputs <= 10; ++requiredInputs) {
            Out o(VERSION_SELECTOR);
            for (int i = 0; i < requiredInputs; ++i) {
              o.putInt32(0);
            }
            Obj mX(o.data(), o.length());
            int totalInputs = 0;
            BSLX_TESTINSTREAM_EXCEPTION_TEST_BEGIN(mX) {
                mX.reset();
                for (int i = 0; i < requiredInputs; ++i) {
                    ++totalInputs;
                    int v = 0;
                    mX.getInt32(v);
                }
            } BSLX_TESTINSTREAM_EXCEPTION_TEST_END

#ifdef BDE_BUILD_TARGET_EXC
            // NOTE: sum(i) for i = 1 .. n == i * (i + 1) / 2 and for the above
            // we want i + sum(i)_1_n (the number of inputs for the successful
            // pass plus all the failure inputs)

            LOOP_ASSERT(requiredInputs, totalInputs == (requiredInputs
                                                        * (requiredInputs + 3)
                                                        / 2));
#else
            // NOTE: without exceptions, totalInputs should be the same as
            // required inputs

            LOOP_ASSERT(requiredInputs, totalInputs == requiredInputs);
#endif
        }
      } break;
      case 31: {
        // --------------------------------------------------------------------
        // UNEXTERNALIZATION FREE OPERATOR
        //   Verify 'operator>>' works correctly.
        //
        // Concerns:
        //: 1 The method inline-forwards to implementation correctly.
        //:
        //: 2 Invocations of the method can be chained.
        //
        // Plan:
        //: 1 Externalize a set of values to an out stream.
        //:
        //: 2 Unexternalize the values and verify the values match the initial
        //:   values.  (C-1)
        //:
        //: 3 Unexternalize a set of values from the stream in one code line.
        //:   (C-2)
        //
        // Testing:
        //   TestInStream& operator>>(TestInStream&, TYPE& value);
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "operator>>" << endl
                          << "==========" << endl;

        {
            char initial = 'a';
            char value = 'b';
            Out o(VERSION_SELECTOR);
            o << initial;
            Obj mX(o.data(), o.length());
            mX >> value;
            ASSERT(value == initial);
        }
        {
            double initial = 7.0;
            double value = 1.0;
            Out o(VERSION_SELECTOR);
            o << initial;
            Obj mX(o.data(), o.length());
            mX >> value;
            ASSERT(value == initial);
        }
        {
            bsl::vector<int> initial;
            bsl::vector<int> value;
            value.push_back(3);
            for (int i = 0; i < 5; ++i) {
                Out o(VERSION_SELECTOR);
                o << initial;
                Obj mX(o.data(), o.length());
                mX >> value;
                LOOP_ASSERT(i, value == initial);
                initial.push_back(i);
            }
        }
        {
            float initial1 = 3.0;
            float value1 = 1.0;
            bsl::string initial2 = "hello";
            bsl::string value2 = "bye";
            short initial3 = 2;
            short value3 = 1;
            Out o(VERSION_SELECTOR);
            o << initial1 << initial2 << initial3;
            Obj mX(o.data(), o.length());
            mX >> value1 >> value2 >> value3;
            ASSERT(value1 == initial1);
            ASSERT(value2 == initial2);
            ASSERT(value3 == initial3);
        }

      } break;
      case 30: {
        // --------------------------------------------------------------------
        // GET STRING TEST:
        //   Verify this method unexternalizes the expected values.
        //
        // Concerns:
        //: 1 The method unexternalizes the expected values.
        //:
        //: 2 Unexternalization position does not effect output.
        //
        // Plan:
        //: 1 Unexternalize at different offsets and verify the values.  (C-1,
        //:   C-2)
        //
        // Testing:
        //   getString(bsl::string& variable);
        // --------------------------------------------------------------------

        if (verbose) {
            cout << endl
                 << "GET STRING TEST" << endl
                 << "===============" << endl;
        }

        if (verbose) {
            cout << "\nTesting 'getString(bsl::string&)'." << endl;
        }
        {
            Out o(VERSION_SELECTOR);
            o.putString(bsl::string("alpha"));    o.putInt8(0xFF);
            o.putString(bsl::string("beta")) ;    o.putInt8(0xFE);
            o.putString(bsl::string("gamma"));    o.putInt8(0xFD);

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            if (veryVerbose) { P(X) }
            char marker;
            bsl::string val;
            mX.getString(val);          mX.getInt8(marker);
            ASSERT(val == "alpha");    ASSERT('\xFF' == marker);
            mX.getString(val);          mX.getInt8(marker);
            ASSERT(val == "beta");     ASSERT('\xFE' == marker);
            mX.getString(val);          mX.getInt8(marker);
            ASSERT(val == "gamma");    ASSERT('\xFD' == marker);
            ASSERT(X);
            ASSERT(X.isEmpty());
            ASSERT(X.cursor() == X.length());
        }
        {
            Out o(VERSION_SELECTOR);
            o.putString(bsl::string("alpha"));    o.putInt8(0xFF);
            o.makeNextInvalid();
            o.putString(bsl::string("beta")) ;    o.putInt8(0xFE);
            o.putString(bsl::string("gamma"));    o.putInt8(0xFD);

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            if (veryVerbose) { P(X) }
            char marker;
            bsl::string val;
            mX.getString(val);          mX.getInt8(marker);
            ASSERT(val == "alpha");    ASSERT('\xFF' == marker);
            mX.setQuiet(1);
            mX.getString(val);
            ASSERT(!X);
            ASSERT(false == X.isEmpty());
            ASSERT(X.cursor() != X.length());
        }
      } break;
      case 29: {
        // --------------------------------------------------------------------
        // GET LENGTH AND VERSION TEST:
        //   Verify these methods unexternalize the expected values.
        //
        // Concerns:
        //: 1 'getLength' correctly inverts 'putLength'.
        //:
        //: 2 The methods unexternalize the expected values.
        //:
        //: 3 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of length values and verify 'getLength'
        //:   inverts 'putLength'.  (C-1)
        //:
        //: 2 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-2, C-3)
        //
        // Testing:
        //   getLength(int &variable);
        //   getVersion(int &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET LENGTH AND VERSION TEST" << endl
                                  << "===========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getLength'." << endl;
        {
            for (int len = 0; len <= 512; ++len) {
                TestOutStream out(VERSION_SELECTOR);
                out.putVersion(1);
                out.putLength(len);
                TestInStream in(out.data(), out.length());
                int tmp;
                in.getVersion(tmp);
                in.getLength(tmp);
                LOOP_ASSERT(len, len == tmp);
            }
        }

        if (verbose) cout << "\nTesting 'getVersion'." << endl;
        {
            typedef int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getVersion;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "C0123",         4,         { VC[0], VC[1], VC[2], VC[3] }    },
         { L_, "C4567",         4,         { VC[4], VC[5], VC[6], VC[7] }    },
         // streams containing incompatible data types
         { L_, "A0 C1234",      5,         { 0 }                             },
         { L_, "C0 B1 C234",    5,         { VC[0] }                         },
         { L_, "C01 E2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C012 F3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C0123 G4",      5,         { VC[0], VC[1], VC[2], VC[3] }    },
         { L_, "C012 H3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C01 I2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C0 J1 C234",    5,         { VC[0] }                         },
         { L_, "K0 C1234",      5,         { 0 }                             },
         { L_, "C0 L1 C234",    5,         { VC[0] }                         },
         { L_, "C01 M2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C012 N3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C0123 O4",      5,         { VC[0], VC[1], VC[2], VC[3] }    },
         { L_, "C012 P3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C01 Q2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C0 R1 C234",    5,         { VC[0] }                         },
         { L_, "S0 C1234",      5,         { 0 }                             },
         { L_, "C0 T1 C234",    5,         { VC[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 28: {
        // --------------------------------------------------------------------
        // TESTING 'reset'
        //   Verify the 'reset' methods work correctly.
        //
        // Concerns:
        //: 1 Every method sets the buffer and length correctly.
        //:
        //: 2 Every method sets the cursor to zero.
        //:
        //: 3 Every method marks the stream valid.
        //:
        //: 4 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Initialize an input stream, read some data to ensure the cursor
        //:   is not zero, and invalidate the stream.
        //:
        //: 2 Call the 'reset' method and verify the buffer and length are
        //:   correctly assigned, the cursor is zero, and the stream is valid.
        //:   (C-1..3)
        //:
        //: 3 Verify defensive checks are triggered for invalid values.  (C-4)
        //
        // Testing:
        //   void reset(const char *buffer, bsl::size_t numBytes);
        //   void reset(const bslstl::StringRef& srcData);
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "TESTING 'reset'" << endl
                          << "===============" << endl;

        {
            Out o(VERSION_SELECTOR);
            o.putString(bsl::string("alpha"));
            o.putString(bsl::string("beta"));
            o.putString(bsl::string("gamma"));

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            if (veryVerbose) { P(X) }
            bsl::string val;
            mX.getString(val);
            mX.invalidate();
            ASSERT(0 != X.cursor());
            ASSERT(false == X.isValid());

            mX.reset();
            ASSERT(o.data() == X.data());
            ASSERT(0 == X.cursor());
            ASSERT(o.length() == X.length());
            ASSERT(X.isValid());
        }

        {
            Out o(VERSION_SELECTOR);
            o.putString(bsl::string("alpha"));
            o.putString(bsl::string("beta"));
            o.putString(bsl::string("gamma"));

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            if (veryVerbose) { P(X) }
            bsl::string val;
            mX.getString(val);
            mX.invalidate();
            ASSERT(0 != X.cursor());
            ASSERT(false == X.isValid());

            const char        *buffer = "abc";
            const bsl::size_t  LEN = 3;
            mX.reset(buffer, LEN);
            ASSERT(buffer == X.data());
            ASSERT(0 == X.cursor());
            ASSERT(LEN == X.length());
            ASSERT(X.isValid());
        }

        {
            Out o(VERSION_SELECTOR);
            o.putString(bsl::string("alpha"));
            o.putString(bsl::string("beta"));
            o.putString(bsl::string("gamma"));

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            if (veryVerbose) { P(X) }
            bsl::string val;
            mX.getString(val);
            mX.invalidate();
            ASSERT(0 != X.cursor());
            ASSERT(false == X.isValid());

            const char        *buffer = "abc";
            const bsl::size_t  LEN = 3;
            bslstl::StringRef stringRef(buffer, LEN);
            mX.reset(stringRef);
            ASSERT(buffer == X.data());
            ASSERT(0 == X.cursor());
            ASSERT(LEN == X.length());
            ASSERT(X.isValid());
        }

        if (verbose)
            cout << "\nNegative Testing." << endl;
        {
            bsls::AssertTestHandlerGuard guard;

            Obj mX;
            ASSERT_SAFE_PASS(mX.reset(0, 0));
            ASSERT_SAFE_FAIL(mX.reset(0, 1));
        }
      } break;
      case 27: {
        // --------------------------------------------------------------------
        // INPUT LIMIT EXCEPTION TEST:
        //   Verify the 'setInputLimit' and 'inputLimit' methods work
        //   correctly.  Of particular concern is the verification that an
        //   exception is thrown when the input limit is exhausted.  See the
        //   descriptions of the testing mechanisms 'testGetArrayInputLimit'
        //   (for array input methods) and 'testGetScalarInputLimit' (for
        //   scalar input methods) for more detailed information.
        //
        // Concerns:
        //: 1 'setInputLimit' works correctly.
        //:
        //: 2 'inputLimit' works correctly.
        //
        // Plan:
        //: 1 Ensure every input method correctly modifies the input limit and
        //    throws an exception when the input limit is exceeded.  (C-1..2)
        //
        // Testing:
        //   void setInputLimit(int limit);
        //   int inputLimit() const;
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "INPUT LIMIT EXCEPTION TEST" << endl
                                  << "==========================" << endl;
        {
            static const InputLimitTestTable DATA[] = {
                //L#  inputLimit  numInput  willThrow  numSuccessInput
                //--  ----------  --------  ---------  ---------------
                { L_,     0,          0,        0,           0        },
                { L_,     0,          1,        1,           0        },
                { L_,     1,          1,        0,           1        },
                { L_,     0,          2,        1,           0        },
                { L_,     1,          2,        1,           1        },
                { L_,     2,          2,        0,           2        },
                { L_,     0,          3,        1,           0        },
                { L_,     1,          3,        1,           1        },
                { L_,     2,          3,        1,           2        },
                { L_,     3,          3,        0,           3        },
            };
            const int NUM_DATA = static_cast<int>(sizeof DATA / sizeof *DATA);

            static const char *SPECS[] = {
                                   "A123", "B123", "C123", "D123",
                                   "E123", "F123", "M123", "N123",
                                   "G123", "H123", "O123", "P123",
                                   "Q123", "R123", "S123", "T123",
                                   "I123", "J123", "K123", "L123",
                                   0}; // Null string required as last element.

            typedef TypeCode TC;

        typedef bslmf::TypeList20<
            GetScalar<char,                &Obj::getInt8,    TC::e_INT8   >,
            GetScalar<signed char,         &Obj::getInt8,    TC::e_INT8   >,
            GetScalar<char,                &Obj::getUint8,   TC::e_UINT8  >,
            GetScalar<unsigned char,       &Obj::getUint8,   TC::e_UINT8  >,
            GetScalar<short,               &Obj::getInt16,   TC::e_INT16  >,
            GetScalar<unsigned short,      &Obj::getUint16,  TC::e_UINT16 >,
            GetScalar<int,                 &Obj::getInt24,   TC::e_INT24  >,
            GetScalar<unsigned int,        &Obj::getUint24,  TC::e_UINT24 >,
            GetScalar<int,                 &Obj::getInt32,   TC::e_INT32  >,
            GetScalar<unsigned int,        &Obj::getUint32,  TC::e_UINT32 >,
            GetScalar<bsls::Types::Int64,  &Obj::getInt40,   TC::e_INT40  >,
            GetScalar<bsls::Types::Uint64, &Obj::getUint40,  TC::e_UINT40 >,
            GetScalar<bsls::Types::Int64,  &Obj::getInt48,   TC::e_INT48  >,
            GetScalar<bsls::Types::Uint64, &Obj::getUint48,  TC::e_UINT48 >,
            GetScalar<bsls::Types::Int64,  &Obj::getInt56,   TC::e_INT56  >,
            GetScalar<bsls::Types::Uint64, &Obj::getUint56,  TC::e_UINT56 >,
            GetScalar<bsls::Types::Int64,  &Obj::getInt64,   TC::e_INT64  >,
            GetScalar<bsls::Types::Uint64, &Obj::getUint64,  TC::e_UINT64 >,
            GetScalar<float,               &Obj::getFloat32, TC::e_FLOAT32>,
            GetScalar<double,              &Obj::getFloat64, TC::e_FLOAT64>
            >::Type List;

            ForEachIn<List>::testInputLimit(DATA, NUM_DATA, SPECS);
        }
        {
            static const InputLimitTestTable DATA[] = {
                //L#  inputLimit  numInput  willThrow  numSuccessInput
                //--  ----------  --------  ---------  ---------------
                { L_,     0,          0,        0,           0        },
                { L_,     0,          1,        1,           0        },
                { L_,     1,          1,        0,           1        },
                { L_,     0,          2,        1,           0        },
                { L_,     1,          2,        1,           1        },
                { L_,     2,          2,        0,           2        },
                { L_,     0,          3,        1,           0        },
                { L_,     1,          3,        1,           1        },
                { L_,     2,          3,        1,           2        },
                { L_,     3,          3,        0,           3        },
            };
            const int NUM_DATA = static_cast<int>(sizeof DATA / sizeof *DATA);

            static const char *SPECS[] = {
                                   "a3a3a3", "b3b3b3", "c3c3c3", "d3d3d3",
                                   "e3e3e3", "f3f3f3", "m3m3m3", "n3n3n3",
                                   "g3g3g3", "h3h3h3", "o3o3o3", "p3p3p3",
                                   "q3q3q3", "r3r3r3", "s3s3s3", "t3t3t3",
                                   "i3i3i3", "j3j3j3", "k3k3k3", "l3l3l3",
                                   0}; // Null string required as last element.

            typedef TypeCode TC;

 typedef bslmf::TypeList20<
     GetArray<char,                &Obj::getArrayInt8,    TC::e_INT8,    3>,
     GetArray<signed char,         &Obj::getArrayInt8,    TC::e_INT8,    3>,
     GetArray<char,                &Obj::getArrayUint8,   TC::e_UINT8,   3>,
     GetArray<unsigned char,       &Obj::getArrayUint8,   TC::e_UINT8,   3>,
     GetArray<short,               &Obj::getArrayInt16,   TC::e_INT16,   3>,
     GetArray<unsigned short,      &Obj::getArrayUint16,  TC::e_UINT16,  3>,
     GetArray<int,                 &Obj::getArrayInt24,   TC::e_INT24,   3>,
     GetArray<unsigned int,        &Obj::getArrayUint24,  TC::e_UINT24,  3>,
     GetArray<int,                 &Obj::getArrayInt32,   TC::e_INT32,   3>,
     GetArray<unsigned int,        &Obj::getArrayUint32,  TC::e_UINT32,  3>,
     GetArray<bsls::Types::Int64,  &Obj::getArrayInt40,   TC::e_INT40,   3>,
     GetArray<bsls::Types::Uint64, &Obj::getArrayUint40,  TC::e_UINT40,  3>,
     GetArray<bsls::Types::Int64,  &Obj::getArrayInt48,   TC::e_INT48,   3>,
     GetArray<bsls::Types::Uint64, &Obj::getArrayUint48,  TC::e_UINT48,  3>,
     GetArray<bsls::Types::Int64,  &Obj::getArrayInt56,   TC::e_INT56,   3>,
     GetArray<bsls::Types::Uint64, &Obj::getArrayUint56,  TC::e_UINT56,  3>,
     GetArray<bsls::Types::Int64,  &Obj::getArrayInt64,   TC::e_INT64,   3>,
     GetArray<bsls::Types::Uint64, &Obj::getArrayUint64,  TC::e_UINT64,  3>,
     GetArray<float,               &Obj::getArrayFloat32, TC::e_FLOAT32, 3>,
     GetArray<double,              &Obj::getArrayFloat64, TC::e_FLOAT64, 3>
     >::Type List;

            ForEachIn<List>::testInputLimit(DATA, NUM_DATA, SPECS);
        }

        // Test the residual methods: 'getLength', 'getVersion', and
        // 'getString'.

#ifdef BDE_BUILD_TARGET_EXC
        { // 'getLength'
            Out o(VERSION_SELECTOR);
            o.putLength(1);
            o.putLength(2);
            o.putLength(3);
            for (int inputLimit = 0; inputLimit < 3; ++inputLimit) {
                Obj mX(o.data(), o.length());  const Obj& X = mX;
                mX.setInputLimit(inputLimit);

                bool thrown = false;

                int value;
                int numInput;
                try {
                    for (numInput = 0; numInput <= inputLimit; ++numInput) {
                        mX.getLength(value);
                    }
                }
                catch (TestInStreamException& e) {
                    thrown = true;
                    LOOP2_ASSERT(inputLimit,
                                 numInput,
                                 TypeCode::e_INT8 == e.dataType());
                }
                LOOP_ASSERT(inputLimit, inputLimit == numInput);
                LOOP_ASSERT(inputLimit, true == thrown);
                LOOP_ASSERT(inputLimit, X.inputLimit() < 0);

                // ensure that once input limit is exceeded and exception has
                // been thrown, then no exception will be thrown again
                mX.seek(0);
                try {
                    for (numInput = 0; numInput <= inputLimit; ++numInput) {
                        mX.getLength(value);
                    }
                }
                catch (TestInStreamException& e) {
                    LOOP2_ASSERT(inputLimit, numInput,
                                 0 && "\t*** Unexpected exception ***\n");
                }
            }
        }
        { // 'getVersion'
            Out o(VERSION_SELECTOR);
            o.putVersion(1);
            o.putVersion(2);
            o.putVersion(3);
            for (int inputLimit = 0; inputLimit < 3; ++inputLimit) {
                Obj mX(o.data(), o.length());  const Obj& X = mX;
                mX.setInputLimit(inputLimit);

                bool thrown = false;

                int value;
                int numInput;
                try {
                    for (numInput = 0; numInput <= inputLimit; ++numInput) {
                        mX.getVersion(value);
                    }
                }
                catch (TestInStreamException& e) {
                    thrown = true;
                    LOOP2_ASSERT(inputLimit,
                                 numInput,
                                 TypeCode::e_UINT8 == e.dataType());
                }
                LOOP_ASSERT(inputLimit, inputLimit == numInput);
                LOOP_ASSERT(inputLimit, true == thrown);
                LOOP_ASSERT(inputLimit, X.inputLimit() < 0);

                // ensure that once input limit is exceeded and exception has
                // been thrown, then no exception will be thrown again
                mX.seek(0);
                try {
                    for (numInput = 0; numInput <= inputLimit; ++numInput) {
                        mX.getVersion(value);
                    }
                }
                catch (TestInStreamException& e) {
                    LOOP2_ASSERT(inputLimit, numInput,
                                 0 && "\t*** Unexpected exception ***\n");
                }
            }
        }
        { // 'getString'
            Out o(VERSION_SELECTOR);
            o.putString(bsl::string("aaa"));
            o.putString(bsl::string("ababa"));
            o.putString(bsl::string("abcbabcba"));
            for (int inputLimit = 0; inputLimit < 3; ++inputLimit) {
                Obj mX(o.data(), o.length());  const Obj& X = mX;
                mX.setInputLimit(inputLimit);

                bool thrown = false;

                bsl::string value;
                int numInput;
                try {
                    for (numInput = 0; numInput <= inputLimit; ++numInput) {
                        mX.getString(value);
                    }
                }
                catch (TestInStreamException& e) {
                    thrown = true;
                    LOOP2_ASSERT(inputLimit,
                                 numInput,
                                 TypeCode::e_INT8 == e.dataType());
                }
                LOOP_ASSERT(inputLimit, inputLimit == numInput);
                LOOP_ASSERT(inputLimit, true == thrown);
                LOOP_ASSERT(inputLimit, X.inputLimit() < 0);

                // ensure that once input limit is exceeded and exception has
                // been thrown, then no exception will be thrown again
                mX.seek(0);
                try {
                    for (numInput = 0; numInput <= inputLimit; ++numInput) {
                        mX.getString(value);
                    }
                }
                catch (TestInStreamException& e) {
                    LOOP2_ASSERT(inputLimit, numInput,
                                 0 && "\t*** Unexpected exception ***\n");
                }
            }
        }
#endif

        if (verbose) cout << endl << "GET/SET INPUT LIMIT TEST" << endl
                                  << "========================" << endl;

        if (verbose)
            cout << "\nTesting 'setInputLimit' and 'inputLimit'." << endl;
        {
            Obj mX;  const Obj& X = mX;
            ASSERT(  0 >  X.inputLimit());
            mX.setInputLimit(0);
            ASSERT(  0 == X.inputLimit());
            mX.setInputLimit(10);
            ASSERT( 10 == X.inputLimit());
            mX.setInputLimit(-10);
            ASSERT(-10 == X.inputLimit());
        }
      } break;
      case 26: {
        // --------------------------------------------------------------------
        // SEEK/RESET TEST:
        //   Verify the methods work correctly.
        //
        // Concerns:
        //: 1 'seek' works correctly.
        //:
        //: 2 'reset' works correctly.
        //
        // Plan:
        //: 1 Create a 'TestInStream' object initialized with arbitrary data.
        //:
        //: 2 Invalidate the stream.
        //:
        //: 3 Invoke its 'seek' method with varying values.
        //:
        //: 4 Verify that the resulting stream is valid and its cursor is
        //:   correctly modified.  (C-1)
        //:
        //: 5 Use 'seek' to modify the stream's cursor to varying values.
        //:
        //: 6 Invalidate the stream and then invoke its 'reset' method.
        //:
        //: 7 Verify that the resulting stream is valid and its cursor is 0.
        //:   (C-2)
        //
        // Testing:
        //   void seek(bsl::size_t offset);
        //   void reset();
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "SEEK/RESET TEST" << endl
                                  << "===============" << endl;

        if (verbose) cout << "\nTesting 'seek' and 'reset'." << endl;
        {
            const char *SPEC = "k10 k10 k10 k10"; // fairly long stream
            Out o(VERSION_SELECTOR);
            int res = g(&o, SPEC);          ASSERT( 1 == res);
            Obj mX(o.data(), o.length());  const Obj& X = mX;
            ASSERT( 0 == X.cursor());

            mX.invalidate();                 ASSERT(!X);
            mX.seek(10);     ASSERT(X);
            ASSERT(10 == X.cursor());

            mX.invalidate();                 ASSERT(!X);
            mX.seek(5);      ASSERT(X);
            ASSERT( 5 == X.cursor());

            mX.invalidate();                 ASSERT(!X);
            mX.seek(0);      ASSERT(X);
            ASSERT( 0 == X.cursor());

            mX.invalidate();                 ASSERT(!X);
            mX.reset();      ASSERT(X);
            ASSERT( 0 == X.cursor());

            mX.seek(5);
            mX.invalidate();                 ASSERT(!X);
            mX.reset();      ASSERT(X);
            ASSERT( 0 == X.cursor());

            mX.seek(10);
            mX.invalidate();                 ASSERT(!X);
            mX.reset();      ASSERT(X);
            ASSERT( 0 == X.cursor());
        }
      } break;
      case 25: {
        // --------------------------------------------------------------------
        // GET 64-BIT FLOAT ARRAY TEST:
        //   Verify this method unexternalizes the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The method unexternalizes the expected values.
        //:
        //: 2 The method implements the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayFloat64(double *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 64-BIT FLOAT ARRAY TEST" << endl
                                  << "===========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayFloat64'." << endl;
        {
            typedef double ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayFloat64;
            const ElemType *V_ORIG = VL;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "l0",          1,        1,         { 0 },         { 0 }       },
        { L_, "l1",          1,        1,         { 1 },         { 1 }       },
        { L_, "l2",          1,        1,         { 2 },         { 2 }       },
        { L_, "l3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 l2 l3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "l4 b5 l6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "l7 l8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "l1 d2 l3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 l5 l6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "l7 f8 l9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "l1 l2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "l4 h5 l6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "i7 l8 l9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "l1 j2 l3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "l4 l5 k6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "l7 l8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "l1 n2 l3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 l5 l6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "l7 p8 l9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "l1 l2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "l1 s2 l3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 l5 l6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "l1 q2 l3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 24: {
        // --------------------------------------------------------------------
        // GET 32-BIT FLOAT ARRAY TEST:
        //   Verify this method unexternalizes the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The method unexternalizes the expected values.
        //:
        //: 2 The method implements the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayFloat32(float *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 32-BIT FLOAT ARRAY TEST" << endl
                                  << "===========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayFloat32'." << endl;
        {
            typedef float ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayFloat32;
            const ElemType *V_ORIG = VK;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "k0",          1,        1,         { 0 },         { 0 }       },
        { L_, "k1",          1,        1,         { 1 },         { 1 }       },
        { L_, "k2",          1,        1,         { 2 },         { 2 }       },
        { L_, "k3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 k2 k3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "k4 b5 k6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "k7 k8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "k1 d2 k3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 k5 k6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "k7 f8 k9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "k1 k2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "k4 h5 k6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "i7 k8 k9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "k1 j2 k3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "k4 k5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "k7 k8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "k1 n2 k3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 k5 k6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "k7 p8 k9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "k1 k2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "k1 s2 k3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 k5 k6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "k1 q2 k3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 23: {
        // --------------------------------------------------------------------
        // GET 64-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayInt64(bsls::Types::Int64 *variables, int numVariables);
        //   getArrayUint64(bsls::Types::Uint64 *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 64-BIT INTEGER ARRAYS TEST" << endl
                                  << "==============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt64'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt64;
            const ElemType *V_ORIG = VI;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "i0",          1,        1,         { 0 },         { 0 }       },
        { L_, "i1",          1,        1,         { 1 },         { 1 }       },
        { L_, "i2",          1,        1,         { 2 },         { 2 }       },
        { L_, "i3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 i2 i3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "i4 b5 i6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "i7 i8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "i1 d2 i3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 i5 i6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "i7 f8 i9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "i1 i2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "i4 h5 i6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 i8 i9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "i1 k2 i3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "i4 i5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "i7 i8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "i1 n2 i3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 i5 i6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "i7 p8 i9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "i1 i2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "i1 s2 i3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 i5 i6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "i1 q2 i3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint64'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint64;
            const ElemType *V_ORIG = VJ;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "j0",          1,        1,      { 0 },            { 0 }       },
        { L_, "j1",          1,        1,      { 1 },            { 1 }       },
        { L_, "j2",          1,        1,      { 2 },            { 2 }       },
        { L_, "j3",          1,        1,      { 3 },            { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 j2 j3",    0,        3,      { 1, 2, 3 },      { 0, 0, 0 } },
        { L_, "j4 b5 j6",    0,        3,      { 4, 5, 6 },      { 4, 0, 0 } },
        { L_, "j7 j8 c9",    0,        3,      { 7, 8, 9 },      { 7, 8, 0 } },
        { L_, "j1 d2 j3",    0,        3,      { 1, 2, 3 },      { 1, 0, 0 } },
        { L_, "e4 j5 j6",    0,        3,      { 4, 5, 6 },      { 0, 0, 0 } },
        { L_, "j7 f8 j9",    0,        3,      { 7, 8, 9 },      { 7, 0, 0 } },
        { L_, "j1 j2 g3",    0,        3,      { 1, 2, 3 },      { 1, 2, 0 } },
        { L_, "j4 h5 j6",    0,        3,      { 4, 5, 6 },      { 4, 0, 0 } },
        { L_, "i7 j8 j9",    0,        3,      { 7, 8, 9 },      { 0, 0, 0 } },
        { L_, "j1 k2 j3",    0,        3,      { 1, 2, 3 },      { 1, 0, 0 } },
        { L_, "j4 j5 l6",    0,        3,      { 4, 5, 6 },      { 4, 5, 0 } },
        { L_, "j7 j8 m9",    0,        3,      { 7, 8, 9 },      { 7, 8, 0 } },
        { L_, "j1 n2 j3",    0,        3,      { 1, 2, 3 },      { 1, 0, 0 } },
        { L_, "o4 j5 j6",    0,        3,      { 4, 5, 6 },      { 0, 0, 0 } },
        { L_, "j7 p8 j9",    0,        3,      { 7, 8, 9 },      { 7, 0, 0 } },
        { L_, "j1 j2 r3",    0,        3,      { 1, 2, 3 },      { 1, 2, 0 } },
        { L_, "j1 s2 j3",    0,        3,      { 1, 2, 3 },      { 1, 0, 0 } },
        { L_, "t4 j5 j6",    0,        3,      { 4, 5, 6 },      { 0, 0, 0 } },
        { L_, "j1 q2 j3",    0,        3,      { 1, 2, 3 },      { 1, 0, 0 } },
            };

            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 22: {
        // --------------------------------------------------------------------
        // GET 56-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayInt56(bsls::Types::Int64 *variables, int numVariables);
        //   getArrayUint56(bsls::Types::Uint64 *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 56-BIT INTEGER ARRAYS TEST" << endl
                                  << "==============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt56'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt56;
            const ElemType *V_ORIG = VS;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "s0",          1,        1,         { 0 },         { 0 }       },
        { L_, "s1",          1,        1,         { 1 },         { 1 }       },
        { L_, "s2",          1,        1,         { 2 },         { 2 }       },
        { L_, "s3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 s2 s3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "s4 b5 s6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "s7 s8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "s1 d2 s3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 s5 s6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "s7 f8 s9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "s1 s2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "s4 h5 s6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 s8 s9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "s1 k2 s3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "s4 s5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "s7 s8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "s1 n2 s3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 s5 s6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "s7 p8 s9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "s1 s2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "s1 i2 s3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 s5 s6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "s1 q2 s3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint56'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint56;
            const ElemType *V_ORIG = VT;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "t0",          1,        1,         { 0 },         { 0 }       },
        { L_, "t1",          1,        1,         { 1 },         { 1 }       },
        { L_, "t2",          1,        1,         { 2 },         { 2 }       },
        { L_, "t3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 t2 t3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "t4 b5 t6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "t7 t8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "t1 d2 t3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 t5 t6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "t7 f8 t9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "t1 t2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "t4 h5 t6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "i7 t8 t9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "t1 k2 t3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 t5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "t7 t8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "t1 n2 t3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 t5 t6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "t7 p8 t9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "t1 t2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "t1 s2 t3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "j4 t5 t6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "t1 q2 t3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };

            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 21: {
        // --------------------------------------------------------------------
        // GET 48-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayInt48(bsls::Types::Int64 *variables, int numVariables);
        //   getArrayUint48(bsls::Types::Uint64 *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 48-BIT INTEGER ARRAYS TEST" << endl
                                  << "==============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt48'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt48;
            const ElemType *V_ORIG = VQ;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "q0",          1,        1,         { 0 },         { 0 }       },
        { L_, "q1",          1,        1,         { 1 },         { 1 }       },
        { L_, "q2",          1,        1,         { 2 },         { 2 }       },
        { L_, "q3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 q2 q3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "q4 b5 q6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "q7 q8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "q1 d2 q3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 q5 q6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "q7 f8 q9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "q1 q2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "q4 h5 q6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 q8 q9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "q1 k2 q3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "q4 q5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "q7 q8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "q1 n2 q3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 q5 q6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "q7 p8 q9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "q1 q2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "q1 s2 q3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 q5 q6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "q1 i2 q3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint48'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint48;
            const ElemType *V_ORIG = VR;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "r0",          1,        1,         { 0 },         { 0 }       },
        { L_, "r1",          1,        1,         { 1 },         { 1 }       },
        { L_, "r2",          1,        1,         { 2 },         { 2 }       },
        { L_, "r3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 r2 r3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "r4 b5 r6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "r7 r8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "r1 d2 r3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 r5 r6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "r7 f8 r9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "r1 r2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "r4 h5 r6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "i7 r8 r9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "r1 k2 r3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "r4 r5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "r7 r8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "r1 n2 r3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 r5 r6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "r7 p8 r9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "r1 r2 j3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "r1 s2 r3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 r5 r6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "r1 q2 r3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };

            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 20: {
        // --------------------------------------------------------------------
        // GET 40-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayInt40(bsls::Types::Int64 *variables, int numVariables);
        //   getArrayUint40(bsls::Types::Uint64 *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 40-BIT INTEGER ARRAYS TEST" << endl
                                  << "==============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt40'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt40;
            const ElemType *V_ORIG = VO;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "o0",          1,        1,         { 0 },         { 0 }       },
        { L_, "o1",          1,        1,         { 1 },         { 1 }       },
        { L_, "o2",          1,        1,         { 2 },         { 2 }       },
        { L_, "o3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 o2 o3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "o4 b5 o6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "o7 o8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "o1 d2 o3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 o5 o6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "o7 f8 o9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "o1 o2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "o4 h5 o6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 o8 o9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "o1 k2 o3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 o5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "o7 o8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "o1 n2 o3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "i4 o5 o6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "o7 p8 o9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "o1 o2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "o1 s2 o3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 o5 o6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "o1 q2 o3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint40'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint40;
            const ElemType *V_ORIG = VP;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "p0",          1,        1,         { 0 },         { 0 }       },
        { L_, "p1",          1,        1,         { 1 },         { 1 }       },
        { L_, "p2",          1,        1,         { 2 },         { 2 }       },
        { L_, "p3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 p2 p3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "p4 b5 p6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "p7 p8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "p1 d2 p3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 p5 p6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "p7 f8 p9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "p1 p2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "p4 h5 p6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "i7 p8 p9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "p1 k2 p3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "p4 p5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "p7 p8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "p1 n2 p3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 p5 p6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "p7 j8 p9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "p1 p2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "p1 s2 p3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 p5 p6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "p1 q2 p3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };

            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 19: {
        // --------------------------------------------------------------------
        // GET 32-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayInt32(int *variables, int numVariables);
        //   getArrayUint32(unsigned int *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 32-BIT INTEGER ARRAYS TEST" << endl
                                  << "==============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt32'." << endl;
        {
            typedef int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt32;
            const ElemType *V_ORIG = VG;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "g0",          1,        1,         { 0 },         { 0 }       },
        { L_, "g1",          1,        1,         { 1 },         { 1 }       },
        { L_, "g2",          1,        1,         { 2 },         { 2 }       },
        { L_, "g3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 g2 g3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "g4 b5 g6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "g7 g8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "g1 d2 g3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 g5 g6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "g7 f8 g9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "g1 g2 h3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "g4 i5 g6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 g8 g9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "g1 k2 g3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "g4 g5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "g7 g8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "g1 n2 g3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 g5 g6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "g7 p8 g9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "g1 g2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "g1 s2 g3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 g5 g6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "g1 q2 g3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint32'." << endl;
        {
            typedef unsigned int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint32;
            const ElemType *V_ORIG = VH;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "h0",          1,        1,         { 0 },         { 0 }       },
        { L_, "h1",          1,        1,         { 1 },         { 1 }       },
        { L_, "h2",          1,        1,         { 2 },         { 2 }       },
        { L_, "h3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 h2 h3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "h4 b5 h6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "h7 h8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "h1 d2 h3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 h5 h6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "h7 f8 h9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "h1 h2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "h4 i5 h6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 h8 h9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "h1 k2 h3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "h4 h5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "h7 h8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "h1 n2 h3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 h5 h6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "h7 p8 h9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "h1 h2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "h1 s2 h3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 h5 h6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "h1 q2 h3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 18: {
        // --------------------------------------------------------------------
        // GET 24-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayInt24(int *variables, int numVariables);
        //   getArrayUint24(unsigned int *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 24-BIT INTEGER ARRAYS TEST" << endl
                                  << "==============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt24'." << endl;
        {
            typedef int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt24;
            const ElemType *V_ORIG = VM;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "m0",          1,        1,         { 0 },         { 0 }       },
        { L_, "m1",          1,        1,         { 1 },         { 1 }       },
        { L_, "m2",          1,        1,         { 2 },         { 2 }       },
        { L_, "m3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 m2 m3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "m4 b5 m6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "m7 m8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "m1 d2 m3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 m5 m6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "m7 f8 m9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "m1 m2 h3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "m4 i5 m6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 m8 m9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "m1 k2 m3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "m4 m5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "m7 m8 g9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "m1 n2 m3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 m5 m6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "m7 p8 m9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "m1 m2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "m1 s2 m3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 m5 m6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "m1 q2 m3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint24'." << endl;
        {
            typedef unsigned int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint24;
            const ElemType *V_ORIG = VN;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "n0",          1,        1,         { 0 },         { 0 }       },
        { L_, "n1",          1,        1,         { 1 },         { 1 }       },
        { L_, "n2",          1,        1,         { 2 },         { 2 }       },
        { L_, "n3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 n2 n3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "n4 b5 n6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "n7 n8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "n1 d2 n3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 n5 n6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "n7 f8 n9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "n1 n2 g3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "n4 i5 n6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 n8 n9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "n1 k2 n3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "n4 n5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "n7 n8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "n1 h2 n3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 n5 n6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "n7 p8 n9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "n1 n2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "n1 s2 n3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 n5 n6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "n1 q2 n3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 17: {
        // --------------------------------------------------------------------
        // GET 16-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //   getArrayInt16(short *variables, int numVariables);
        //   getArrayUint16(unsigned short *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 16-BIT INTEGER ARRAYS TEST" << endl
                                  << "==============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt16'." << endl;
        {
            typedef short ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt16;
            const ElemType *V_ORIG = VE;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "e0",          1,        1,         { 0 },         { 0 }       },
        { L_, "e1",          1,        1,         { 1 },         { 1 }       },
        { L_, "e2",          1,        1,         { 2 },         { 2 }       },
        { L_, "e3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 e2 e3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "e4 b5 e6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "e7 e8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "e1 d2 e3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "f4 e5 e6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "e7 g8 e9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "e1 e2 h3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "e4 i5 e6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 e8 e9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "e1 k2 e3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 e5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "e7 e8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "e1 n2 e3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 e5 e6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "e7 p8 e9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "e1 e2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "e1 s2 e3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 e5 e6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "e1 q2 e3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint16'." << endl;
        {
            typedef unsigned short ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint16;
            const ElemType *V_ORIG = VF;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "f0",          1,        1,         { 0 },         { 0 }       },
        { L_, "f1",          1,        1,         { 1 },         { 1 }       },
        { L_, "f2",          1,        1,         { 2 },         { 2 }       },
        { L_, "f3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 f2 f3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "f4 b5 f6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "f7 f8 c9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "f1 d2 f3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "e4 f5 f6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "f7 g8 f9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "f1 f2 h3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "f4 i5 f6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "j7 f8 f9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "f1 k2 f3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "f4 f5 l6",    0,        3,         { 4, 5, 6 },   { 4, 5, 0 } },
        { L_, "f7 f8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "f1 n2 f3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 f5 f6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "f7 p8 f9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "f1 f2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "f1 s2 f3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 f5 f6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "f1 q2 f3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 16: {
        // --------------------------------------------------------------------
        // GET 8-BIT INTEGER ARRAYS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetArray'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //:
        //: 3 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..3)
        //
        // Testing:
        //    getArrayInt8(char *variables, int numVariables);
        //    getArrayInt8(signed char *variables, int numVariables);
        //    getArrayUint8(char *variables, int numVariables);
        //    getArrayUint8(unsigned char *variables, int numVariables);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 8-BIT INTEGER ARRAYS TEST" << endl
                                  << "=============================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getArrayInt8' w/ 'char*'." << endl;
        {
            typedef char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt8;
            const ElemType *V_ORIG = VA;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "a0",          1,        1,         { 0 },         { 0 }       },
        { L_, "a1",          1,        1,         { 1 },         { 1 }       },
        { L_, "a2",          1,        1,         { 2 },         { 2 }       },
        { L_, "a3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "c1 a2 a3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "a4 d5 a6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "a7 a8 e9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "a1 f2 a3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "g4 a5 a6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "a7 h8 a9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "a1 a2 i3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "a4 j5 a6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "k7 a8 a9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "a1 l2 a3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "a7 a8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "a1 n2 a3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 a5 a6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "a7 p8 a9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "a1 a2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "a1 s2 a3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 a5 a6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "a1 q2 a3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose)
            cout << "\nTesting 'getArrayInt8' w/ 'signed char*'." << endl;
        {
            typedef signed char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayInt8;
            const ElemType *V_ORIG = VB;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "b0",          1,        1,         { 0 },         { 0 }       },
        { L_, "b1",          1,        1,         { 1 },         { 1 }       },
        { L_, "b2",          1,        1,         { 2 },         { 2 }       },
        { L_, "b3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "c1 b2 b3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "b4 d5 b6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "b7 b8 e9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "b1 f2 b3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "g4 b5 b6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "b7 h8 b9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "b1 b2 i3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "b4 j5 b6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "k7 b8 b9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "b1 l2 b3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "b7 b8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "b1 n2 b3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 b5 b6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "b7 p8 b9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "b1 b2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "b1 s2 b3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 b5 b6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "b1 q2 b3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getArrayUint8' w/ 'char*'." << endl;
        {
            typedef char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint8;
            const ElemType *V_ORIG = VC;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "c0",          1,        1,         { 0 },         { 0 }       },
        { L_, "c1",          1,        1,         { 1 },         { 1 }       },
        { L_, "c2",          1,        1,         { 2 },         { 2 }       },
        { L_, "c3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 c2 c3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "c4 b5 c6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "c7 c8 e9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "c1 f2 c3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "g4 c5 c6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "c7 h8 c9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "c1 c2 i3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "c4 j5 c6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "k7 c8 c9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "c1 l2 c3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "c7 c8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "c1 n2 c3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 c5 c6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "c7 p8 c9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "c1 c2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "c1 s2 c3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 c5 c6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "c1 q2 c3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose)
            cout << "\nTesting 'getArrayUint8' w/ 'unsigned char*'." << endl;
        {
            typedef unsigned char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType*, int);
            const FuncPtr FUNC = &Obj::getArrayUint8;
            const ElemType *V_ORIG = VD;        // base-comparison array

            static const ArrayTestTable DATA[] = {
        //                   expected  # arrays   array lengths  expected
        //L#  spec           validity  to read    to read        array lengths
        //--  -------------  --------  ---------  -------------  -------------
        // read from empty stream
        { L_, "",            0,        1,         { 1 },         { 0 }       },
        // valid streams
        { L_, "d0",          1,        1,         { 0 },         { 0 }       },
        { L_, "d1",          1,        1,         { 1 },         { 1 }       },
        { L_, "d2",          1,        1,         { 2 },         { 2 }       },
        { L_, "d3",          1,        1,         { 3 },         { 3 }       },
        // streams containing incompatible data types
        { L_, "a1 d2 d3",    0,        3,         { 1, 2, 3 },   { 0, 0, 0 } },
        { L_, "d4 b5 d6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "d7 d8 e9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "d1 f2 d3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "g4 d5 d6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "d7 h8 d9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "d1 d2 i3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "d4 j5 d6",    0,        3,         { 4, 5, 6 },   { 4, 0, 0 } },
        { L_, "k7 d8 d9",    0,        3,         { 7, 8, 9 },   { 0, 0, 0 } },
        { L_, "d1 l2 d3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "d7 d8 m9",    0,        3,         { 7, 8, 9 },   { 7, 8, 0 } },
        { L_, "d1 n2 d3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "o4 d5 d6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "d7 p8 d9",    0,        3,         { 7, 8, 9 },   { 7, 0, 0 } },
        { L_, "d1 d2 r3",    0,        3,         { 1, 2, 3 },   { 1, 2, 0 } },
        { L_, "d1 s2 d3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
        { L_, "t4 d5 d6",    0,        3,         { 4, 5, 6 },   { 0, 0, 0 } },
        { L_, "d1 q2 d3",    0,        3,         { 1, 2, 3 },   { 1, 0, 0 } },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetArray<ElemType, FuncPtr>(DATA, DATA_LEN, V_ORIG, FUNC);
        }
      } break;
      case 15: {
        // --------------------------------------------------------------------
        // GET 64-BIT FLOAT TEST:
        //   Verify this method unexternalizes the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The method unexternalizes the expected values.
        //:
        //: 2 The method implements the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getFloat64(double &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 64-BIT FLOAT TEST" << endl
                                  << "=====================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getFloat64'." << endl;
        {
            typedef double ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getFloat64;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "L0123",         4,         { VL[0], VL[1], VL[2], VL[3] }    },
         { L_, "L4567",         4,         { VL[4], VL[5], VL[6], VL[7] }    },
         // streams containing incompatible data types
         { L_, "A0 L1234",      5,         { 0 }                             },
         { L_, "L0 B1 L234",    5,         { VL[0] }                         },
         { L_, "L01 C2 L34",    5,         { VL[0], VL[1] }                  },
         { L_, "L012 D3 L4",    5,         { VL[0], VL[1], VL[2] }           },
         { L_, "L0123 E4",      5,         { VL[0], VL[1], VL[2], VL[3] }    },
         { L_, "L012 F3 L4",    5,         { VL[0], VL[1], VL[2] }           },
         { L_, "L01 G2 L34",    5,         { VL[0], VL[1] }                  },
         { L_, "L0 H1 L234",    5,         { VL[0] }                         },
         { L_, "I0 L1234",      5,         { 0 }                             },
         { L_, "L0 J1 L234",    5,         { VL[0] }                         },
         { L_, "L01 K2 L34",    5,         { VL[0], VL[1] }                  },
         { L_, "L01 M2 L34",    5,         { VL[0], VL[1] }                  },
         { L_, "L012 N3 L4",    5,         { VL[0], VL[1], VL[2] }           },
         { L_, "L0123 O4",      5,         { VL[0], VL[1], VL[2], VL[3] }    },
         { L_, "L012 P3 L4",    5,         { VL[0], VL[1], VL[2] }           },
         { L_, "L01 Q2 L34",    5,         { VL[0], VL[1] }                  },
         { L_, "L0 R1 L234",    5,         { VL[0] }                         },
         { L_, "S0 L1234",      5,         { 0 }                             },
         { L_, "L0 T1 L234",    5,         { VL[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 14: {
        // --------------------------------------------------------------------
        // GET 32-BIT FLOAT TEST:
        //   Verify this method unexternalizes the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The method unexternalizes the expected values.
        //:
        //: 2 The method implements the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getFloat32(float &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 32-BIT FLOAT TEST" << endl
                                  << "=====================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getFloat32'." << endl;
        {
            typedef float ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getFloat32;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "K0123",         4,         { VK[0], VK[1], VK[2], VK[3] }    },
         { L_, "K4567",         4,         { VK[4], VK[5], VK[6], VK[7] }    },
         // streams containing incompatible data types
         { L_, "A0 K1234",      5,         { 0 }                             },
         { L_, "K0 B1 K234",    5,         { VK[0] }                         },
         { L_, "K01 C2 K34",    5,         { VK[0], VK[1] }                  },
         { L_, "K012 D3 K4",    5,         { VK[0], VK[1], VK[2] }           },
         { L_, "K0123 E4",      5,         { VK[0], VK[1], VK[2], VK[3] }    },
         { L_, "K012 F3 K4",    5,         { VK[0], VK[1], VK[2] }           },
         { L_, "K01 G2 K34",    5,         { VK[0], VK[1] }                  },
         { L_, "K0 H1 K234",    5,         { VK[0] }                         },
         { L_, "I0 K1234",      5,         { 0 }                             },
         { L_, "K0 J1 K234",    5,         { VK[0] }                         },
         { L_, "K01 L2 K34",    5,         { VK[0], VK[1] }                  },
         { L_, "K01 M2 K34",    5,         { VK[0], VK[1] }                  },
         { L_, "K012 N3 K4",    5,         { VK[0], VK[1], VK[2] }           },
         { L_, "K0123 O4",      5,         { VK[0], VK[1], VK[2], VK[3] }    },
         { L_, "K012 P3 K4",    5,         { VK[0], VK[1], VK[2] }           },
         { L_, "K01 Q2 K34",    5,         { VK[0], VK[1] }                  },
         { L_, "K0 R1 K234",    5,         { VK[0] }                         },
         { L_, "S0 K1234",      5,         { 0 }                             },
         { L_, "K0 T1 K234",    5,         { VK[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 13: {
        // --------------------------------------------------------------------
        // GET 64-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt64(bsls::Types::Int64 val &variable);
        //   getUint64(bsls::Types::Uint64 val &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 64-BIT INTEGERS TEST" << endl
                                  << "========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt64'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt64;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "I0123",         4,         { VI[0], VI[1], VI[2], VI[3] }    },
         { L_, "I4567",         4,         { VI[4], VI[5], VI[6], VI[7] }    },
         // streams containing incompatible data types
         { L_, "A0 I1234",      5,         { 0 }                             },
         { L_, "I0 B1 I234",    5,         { VI[0] }                         },
         { L_, "I01 C2 I34",    5,         { VI[0], VI[1] }                  },
         { L_, "I012 D3 I4",    5,         { VI[0], VI[1], VI[2] }           },
         { L_, "I0123 E4",      5,         { VI[0], VI[1], VI[2], VI[3] }    },
         { L_, "I012 F3 I4",    5,         { VI[0], VI[1], VI[2] }           },
         { L_, "I01 G2 I34",    5,         { VI[0], VI[1] }                  },
         { L_, "I0 H1 I234",    5,         { VI[0] }                         },
         { L_, "J0 I1234",      5,         { 0 }                             },
         { L_, "I0 K1 I234",    5,         { VI[0] }                         },
         { L_, "I01 L2 I34",    5,         { VI[0], VI[1] }                  },
         { L_, "I01 M2 I34",    5,         { VI[0], VI[1] }                  },
         { L_, "I012 N3 I4",    5,         { VI[0], VI[1], VI[2] }           },
         { L_, "I0123 O4",      5,         { VI[0], VI[1], VI[2], VI[3] }    },
         { L_, "I012 P3 I4",    5,         { VI[0], VI[1], VI[2] }           },
         { L_, "I01 Q2 I34",    5,         { VI[0], VI[1] }                  },
         { L_, "I0 R1 I234",    5,         { VI[0] }                         },
         { L_, "S0 I1234",      5,         { 0 }                             },
         { L_, "I0 T1 I234",    5,         { VI[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint64'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint64;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "J0123",         4,         { VJ[0], VJ[1], VJ[2], VJ[3] }    },
         { L_, "J4567",         4,         { VJ[4], VJ[5], VJ[6], VJ[7] }    },
         // streams containing incompatible data types
         { L_, "A0 J1234",      5,         { 0 }                             },
         { L_, "J0 B1 J234",    5,         { VJ[0] }                         },
         { L_, "J01 C2 J34",    5,         { VJ[0], VJ[1] }                  },
         { L_, "J012 D3 J4",    5,         { VJ[0], VJ[1], VJ[2] }           },
         { L_, "J0123 E4",      5,         { VJ[0], VJ[1], VJ[2], VJ[3] }    },
         { L_, "J012 F3 J4",    5,         { VJ[0], VJ[1], VJ[2] }           },
         { L_, "J01 G2 J34",    5,         { VJ[0], VJ[1] }                  },
         { L_, "J0 H1 J234",    5,         { VJ[0] }                         },
         { L_, "I0 J1234",      5,         { 0 }                             },
         { L_, "J0 K1 J234",    5,         { VJ[0] }                         },
         { L_, "J01 L2 J34",    5,         { VJ[0], VJ[1] }                  },
         { L_, "J01 M2 J34",    5,         { VJ[0], VJ[1] }                  },
         { L_, "J012 N3 J4",    5,         { VJ[0], VJ[1], VJ[2] }           },
         { L_, "J0123 O4",      5,         { VJ[0], VJ[1], VJ[2], VJ[3] }    },
         { L_, "J012 P3 J4",    5,         { VJ[0], VJ[1], VJ[2] }           },
         { L_, "J01 Q2 J34",    5,         { VJ[0], VJ[1] }                  },
         { L_, "J0 R1 J234",    5,         { VJ[0] }                         },
         { L_, "S0 J1234",      5,         { 0 }                             },
         { L_, "J0 T1 J234",    5,         { VJ[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 12: {
        // --------------------------------------------------------------------
        // GET 56-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt56(bsls::Types::Int64 val &variable);
        //   getUint56(bsls::Types::Uint64 val &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 56-BIT INTEGERS TEST" << endl
                                  << "========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt56'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt56;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "S0123",         4,         { VS[0], VS[1], VS[2], VS[3] }    },
         { L_, "S4567",         4,         { VS[4], VS[5], VS[6], VS[7] }    },
         // streams containing incompatible data types
         { L_, "A0 S1234",      5,         { 0 }                             },
         { L_, "S0 B1 S234",    5,         { VS[0] }                         },
         { L_, "S01 C2 S34",    5,         { VS[0], VS[1] }                  },
         { L_, "S012 D3 S4",    5,         { VS[0], VS[1], VS[2] }           },
         { L_, "S0123 E4",      5,         { VS[0], VS[1], VS[2], VS[3] }    },
         { L_, "S012 F3 S4",    5,         { VS[0], VS[1], VS[2] }           },
         { L_, "S01 G2 S34",    5,         { VS[0], VS[1] }                  },
         { L_, "S0 H1 S234",    5,         { VS[0] }                         },
         { L_, "J0 S1234",      5,         { 0 }                             },
         { L_, "S0 K1 S234",    5,         { VS[0] }                         },
         { L_, "S01 L2 S34",    5,         { VS[0], VS[1] }                  },
         { L_, "S01 M2 S34",    5,         { VS[0], VS[1] }                  },
         { L_, "S012 N3 S4",    5,         { VS[0], VS[1], VS[2] }           },
         { L_, "S0123 O4",      5,         { VS[0], VS[1], VS[2], VS[3] }    },
         { L_, "S012 P3 S4",    5,         { VS[0], VS[1], VS[2] }           },
         { L_, "S01 Q2 S34",    5,         { VS[0], VS[1] }                  },
         { L_, "S0 R1 S234",    5,         { VS[0] }                         },
         { L_, "I0 S1234",      5,         { 0 }                             },
         { L_, "S0 T1 S234",    5,         { VS[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint56'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint56;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "T0123",         4,         { VT[0], VT[1], VT[2], VT[3] }    },
         { L_, "T4567",         4,         { VT[4], VT[5], VT[6], VT[7] }    },
         // streams containing incompatible data types
         { L_, "A0 T1234",      5,         { 0 }                             },
         { L_, "T0 B1 T234",    5,         { VT[0] }                         },
         { L_, "T01 C2 T34",    5,         { VT[0], VT[1] }                  },
         { L_, "T012 D3 T4",    5,         { VT[0], VT[1], VT[2] }           },
         { L_, "T0123 E4",      5,         { VT[0], VT[1], VT[2], VT[3] }    },
         { L_, "T012 F3 T4",    5,         { VT[0], VT[1], VT[2] }           },
         { L_, "T01 G2 T34",    5,         { VT[0], VT[1] }                  },
         { L_, "T0 H1 T234",    5,         { VT[0] }                         },
         { L_, "I0 T1234",      5,         { 0 }                             },
         { L_, "T0 K1 T234",    5,         { VT[0] }                         },
         { L_, "T01 L2 T34",    5,         { VT[0], VT[1] }                  },
         { L_, "T01 M2 T34",    5,         { VT[0], VT[1] }                  },
         { L_, "T012 N3 T4",    5,         { VT[0], VT[1], VT[2] }           },
         { L_, "T0123 O4",      5,         { VT[0], VT[1], VT[2], VT[3] }    },
         { L_, "T012 P3 T4",    5,         { VT[0], VT[1], VT[2] }           },
         { L_, "T01 Q2 T34",    5,         { VT[0], VT[1] }                  },
         { L_, "T0 R1 T234",    5,         { VT[0] }                         },
         { L_, "S0 T1234",      5,         { 0 }                             },
         { L_, "T0 J1 T234",    5,         { VT[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 11: {
        // --------------------------------------------------------------------
        // GET 48-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt48(bsls::Types::Int64 val &variable);
        //   getUint48(bsls::Types::Uint64 val &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 48-BIT INTEGERS TEST" << endl
                                  << "========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt48'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt48;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "Q0123",         4,         { VQ[0], VQ[1], VQ[2], VQ[3] }    },
         { L_, "Q4567",         4,         { VQ[4], VQ[5], VQ[6], VQ[7] }    },
         // streams containing incompatible data types
         { L_, "A0 Q1234",      5,         { 0 }                             },
         { L_, "Q0 B1 Q234",    5,         { VQ[0] }                         },
         { L_, "Q01 C2 Q34",    5,         { VQ[0], VQ[1] }                  },
         { L_, "Q012 D3 Q4",    5,         { VQ[0], VQ[1], VQ[2] }           },
         { L_, "Q0123 E4",      5,         { VQ[0], VQ[1], VQ[2], VQ[3] }    },
         { L_, "Q012 F3 Q4",    5,         { VQ[0], VQ[1], VQ[2] }           },
         { L_, "Q01 G2 Q34",    5,         { VQ[0], VQ[1] }                  },
         { L_, "Q0 H1 Q234",    5,         { VQ[0] }                         },
         { L_, "J0 Q1234",      5,         { 0 }                             },
         { L_, "Q0 K1 Q234",    5,         { VQ[0] }                         },
         { L_, "Q01 L2 Q34",    5,         { VQ[0], VQ[1] }                  },
         { L_, "Q01 M2 Q34",    5,         { VQ[0], VQ[1] }                  },
         { L_, "Q012 N3 Q4",    5,         { VQ[0], VQ[1], VQ[2] }           },
         { L_, "Q0123 O4",      5,         { VQ[0], VQ[1], VQ[2], VQ[3] }    },
         { L_, "Q012 P3 Q4",    5,         { VQ[0], VQ[1], VQ[2] }           },
         { L_, "Q01 I2 Q34",    5,         { VQ[0], VQ[1] }                  },
         { L_, "Q0 R1 Q234",    5,         { VQ[0] }                         },
         { L_, "S0 Q1234",      5,         { 0 }                             },
         { L_, "Q0 T1 Q234",    5,         { VQ[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint48'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint48;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "R0123",         4,         { VR[0], VR[1], VR[2], VR[3] }    },
         { L_, "R4567",         4,         { VR[4], VR[5], VR[6], VR[7] }    },
         // streams containing incompatible data types
         { L_, "A0 R1234",      5,         { 0 }                             },
         { L_, "R0 B1 R234",    5,         { VR[0] }                         },
         { L_, "R01 C2 R34",    5,         { VR[0], VR[1] }                  },
         { L_, "R012 D3 R4",    5,         { VR[0], VR[1], VR[2] }           },
         { L_, "R0123 E4",      5,         { VR[0], VR[1], VR[2], VR[3] }    },
         { L_, "R012 F3 R4",    5,         { VR[0], VR[1], VR[2] }           },
         { L_, "R01 G2 R34",    5,         { VR[0], VR[1] }                  },
         { L_, "R0 H1 R234",    5,         { VR[0] }                         },
         { L_, "I0 R1234",      5,         { 0 }                             },
         { L_, "R0 K1 R234",    5,         { VR[0] }                         },
         { L_, "R01 L2 R34",    5,         { VR[0], VR[1] }                  },
         { L_, "R01 M2 R34",    5,         { VR[0], VR[1] }                  },
         { L_, "R012 N3 R4",    5,         { VR[0], VR[1], VR[2] }           },
         { L_, "R0123 O4",      5,         { VR[0], VR[1], VR[2], VR[3] }    },
         { L_, "R012 P3 R4",    5,         { VR[0], VR[1], VR[2] }           },
         { L_, "R01 Q2 R34",    5,         { VR[0], VR[1] }                  },
         { L_, "R0 J1 R234",    5,         { VR[0] }                         },
         { L_, "S0 R1234",      5,         { 0 }                             },
         { L_, "R0 T1 R234",    5,         { VR[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 10: {
        // --------------------------------------------------------------------
        // GET 40-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt40(bsls::Types::Int64 val &variable);
        //   getUint40(bsls::Types::Uint64 val &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 40-BIT INTEGERS TEST" << endl
                                  << "========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt40'." << endl;
        {
            typedef bsls::Types::Int64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt40;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "O0123",         4,         { VO[0], VO[1], VO[2], VO[3] }    },
         { L_, "O4567",         4,         { VO[4], VO[5], VO[6], VO[7] }    },
         // streams containing incompatible data types
         { L_, "A0 O1234",      5,         { 0 }                             },
         { L_, "O0 B1 O234",    5,         { VO[0] }                         },
         { L_, "O01 C2 O34",    5,         { VO[0], VO[1] }                  },
         { L_, "O012 D3 O4",    5,         { VO[0], VO[1], VO[2] }           },
         { L_, "O0123 E4",      5,         { VO[0], VO[1], VO[2], VO[3] }    },
         { L_, "O012 F3 O4",    5,         { VO[0], VO[1], VO[2] }           },
         { L_, "O01 G2 O34",    5,         { VO[0], VO[1] }                  },
         { L_, "O0 H1 O234",    5,         { VO[0] }                         },
         { L_, "J0 O1234",      5,         { 0 }                             },
         { L_, "O0 K1 O234",    5,         { VO[0] }                         },
         { L_, "O01 L2 O34",    5,         { VO[0], VO[1] }                  },
         { L_, "O01 M2 O34",    5,         { VO[0], VO[1] }                  },
         { L_, "O012 N3 O4",    5,         { VO[0], VO[1], VO[2] }           },
         { L_, "O0123 I4",      5,         { VO[0], VO[1], VO[2], VO[3] }    },
         { L_, "O012 P3 O4",    5,         { VO[0], VO[1], VO[2] }           },
         { L_, "O01 Q2 O34",    5,         { VO[0], VO[1] }                  },
         { L_, "O0 R1 O234",    5,         { VO[0] }                         },
         { L_, "S0 O1234",      5,         { 0 }                             },
         { L_, "O0 T1 O234",    5,         { VO[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint40'." << endl;
        {
            typedef bsls::Types::Uint64 ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint40;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "P0123",         4,         { VP[0], VP[1], VP[2], VP[3] }    },
         { L_, "P4567",         4,         { VP[4], VP[5], VP[6], VP[7] }    },
         // streams containing incompatible data types
         { L_, "A0 P1234",      5,         { 0 }                             },
         { L_, "P0 B1 P234",    5,         { VP[0] }                         },
         { L_, "P01 C2 P34",    5,         { VP[0], VP[1] }                  },
         { L_, "P012 D3 P4",    5,         { VP[0], VP[1], VP[2] }           },
         { L_, "P0123 E4",      5,         { VP[0], VP[1], VP[2], VP[3] }    },
         { L_, "P012 F3 P4",    5,         { VP[0], VP[1], VP[2] }           },
         { L_, "P01 G2 P34",    5,         { VP[0], VP[1] }                  },
         { L_, "P0 H1 P234",    5,         { VP[0] }                         },
         { L_, "I0 P1234",      5,         { 0 }                             },
         { L_, "P0 K1 P234",    5,         { VP[0] }                         },
         { L_, "P01 L2 P34",    5,         { VP[0], VP[1] }                  },
         { L_, "P01 M2 P34",    5,         { VP[0], VP[1] }                  },
         { L_, "P012 N3 P4",    5,         { VP[0], VP[1], VP[2] }           },
         { L_, "P0123 O4",      5,         { VP[0], VP[1], VP[2], VP[3] }    },
         { L_, "P012 J3 P4",    5,         { VP[0], VP[1], VP[2] }           },
         { L_, "P01 Q2 P34",    5,         { VP[0], VP[1] }                  },
         { L_, "P0 R1 P234",    5,         { VP[0] }                         },
         { L_, "S0 P1234",      5,         { 0 }                             },
         { L_, "P0 T1 P234",    5,         { VP[0] }                         },

            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 9: {
        // --------------------------------------------------------------------
        // GET 32-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt32(int &variable);
        //   getUint32(unsigned int &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 32-BIT INTEGERS TEST" << endl
                                  << "========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt32'." << endl;
        {
            typedef int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt32;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "G0123",         4,         { VG[0], VG[1], VG[2], VG[3] }    },
         { L_, "G4567",         4,         { VG[4], VG[5], VG[6], VG[7] }    },
         // streams containing incompatible data types
         { L_, "A0 G1234",      5,         { 0 }                             },
         { L_, "G0 B1 G234",    5,         { VG[0] }                         },
         { L_, "G01 C2 G34",    5,         { VG[0], VG[1] }                  },
         { L_, "G012 D3 G4",    5,         { VG[0], VG[1], VG[2] }           },
         { L_, "G0123 E4",      5,         { VG[0], VG[1], VG[2], VG[3] }    },
         { L_, "G012 F3 G4",    5,         { VG[0], VG[1], VG[2] }           },
         { L_, "G01 H2 G34",    5,         { VG[0], VG[1] }                  },
         { L_, "G0 I1 G234",    5,         { VG[0] }                         },
         { L_, "J0 G1234",      5,         { 0 }                             },
         { L_, "G0 K1 G234",    5,         { VG[0] }                         },
         { L_, "G01 L2 G34",    5,         { VG[0], VG[1] }                  },
         { L_, "G01 M2 G34",    5,         { VG[0], VG[1] }                  },
         { L_, "G012 N3 G4",    5,         { VG[0], VG[1], VG[2] }           },
         { L_, "G0123 O4",      5,         { VG[0], VG[1], VG[2], VG[3] }    },
         { L_, "G012 P3 G4",    5,         { VG[0], VG[1], VG[2] }           },
         { L_, "G01 Q2 G34",    5,         { VG[0], VG[1] }                  },
         { L_, "G0 R1 G234",    5,         { VG[0] }                         },
         { L_, "S0 G1234",      5,         { 0 }                             },
         { L_, "G0 T1 G234",    5,         { VG[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint32'." << endl;
        {
            typedef unsigned int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint32;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "H0123",         4,         { VH[0], VH[1], VH[2], VH[3] }    },
         { L_, "H4567",         4,         { VH[4], VH[5], VH[6], VH[7] }    },
         // streams containing incompatible data types
         { L_, "A0 H1234",      5,         { 0 }                             },
         { L_, "H0 B1 H234",    5,         { VH[0] }                         },
         { L_, "H01 C2 H34",    5,         { VH[0], VH[1] }                  },
         { L_, "H012 D3 H4",    5,         { VH[0], VH[1], VH[2] }           },
         { L_, "H0123 E4",      5,         { VH[0], VH[1], VH[2], VH[3] }    },
         { L_, "H012 F3 H4",    5,         { VH[0], VH[1], VH[2] }           },
         { L_, "H01 G2 H34",    5,         { VH[0], VH[1] }                  },
         { L_, "H0 I1 H234",    5,         { VH[0] }                         },
         { L_, "J0 H1234",      5,         { 0 }                             },
         { L_, "H0 K1 H234",    5,         { VH[0] }                         },
         { L_, "H01 L2 H34",    5,         { VH[0], VH[1] }                  },
         { L_, "H01 M2 H34",    5,         { VH[0], VH[1] }                  },
         { L_, "H012 N3 H4",    5,         { VH[0], VH[1], VH[2] }           },
         { L_, "H0123 O4",      5,         { VH[0], VH[1], VH[2], VH[3] }    },
         { L_, "H012 P3 H4",    5,         { VH[0], VH[1], VH[2] }           },
         { L_, "H01 Q2 H34",    5,         { VH[0], VH[1] }                  },
         { L_, "H0 R1 H234",    5,         { VH[0] }                         },
         { L_, "S0 H1234",      5,         { 0 }                             },
         { L_, "H0 T1 H234",    5,         { VH[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 8: {
        // --------------------------------------------------------------------
        // GET 24-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt24(int &variable);
        //   getUint24(unsigned int &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 24-BIT INTEGERS TEST" << endl
                                  << "========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt24'." << endl;
        {
            typedef int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt24;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "M0123",         4,         { VM[0], VM[1], VM[2], VM[3] }    },
         { L_, "M4567",         4,         { VM[4], VM[5], VM[6], VM[7] }    },
         // streams containing incompatible data types
         { L_, "A0 M1234",      5,         { 0 }                             },
         { L_, "M0 B1 M234",    5,         { VM[0] }                         },
         { L_, "M01 C2 M34",    5,         { VM[0], VM[1] }                  },
         { L_, "M012 D3 M4",    5,         { VM[0], VM[1], VM[2] }           },
         { L_, "M0123 E4",      5,         { VM[0], VM[1], VM[2], VM[3] }    },
         { L_, "M012 F3 M4",    5,         { VM[0], VM[1], VM[2] }           },
         { L_, "M01 H2 M34",    5,         { VM[0], VM[1] }                  },
         { L_, "M0 I1 M234",    5,         { VM[0] }                         },
         { L_, "J0 M1234",      5,         { 0 }                             },
         { L_, "M0 K1 M234",    5,         { VM[0] }                         },
         { L_, "M01 L2 M34",    5,         { VM[0], VM[1] }                  },
         { L_, "M01 G2 M34",    5,         { VM[0], VM[1] }                  },
         { L_, "M012 N3 M4",    5,         { VM[0], VM[1], VM[2] }           },
         { L_, "M0123 O4",      5,         { VM[0], VM[1], VM[2], VM[3] }    },
         { L_, "M012 P3 M4",    5,         { VM[0], VM[1], VM[2] }           },
         { L_, "M01 Q2 M34",    5,         { VM[0], VM[1] }                  },
         { L_, "M0 R1 M234",    5,         { VM[0] }                         },
         { L_, "S0 M1234",      5,         { 0 }                             },
         { L_, "M0 T1 M234",    5,         { VM[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint24'." << endl;
        {
            typedef unsigned int ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint24;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "N0123",         4,         { VN[0], VN[1], VN[2], VN[3] }    },
         { L_, "N4567",         4,         { VN[4], VN[5], VN[6], VN[7] }    },
         // streams containing incompatible data types
         { L_, "A0 N1234",      5,         { 0 }                             },
         { L_, "N0 B1 N234",    5,         { VN[0] }                         },
         { L_, "N01 C2 N34",    5,         { VN[0], VN[1] }                  },
         { L_, "N012 D3 N4",    5,         { VN[0], VN[1], VN[2] }           },
         { L_, "N0123 E4",      5,         { VN[0], VN[1], VN[2], VN[3] }    },
         { L_, "N012 F3 N4",    5,         { VN[0], VN[1], VN[2] }           },
         { L_, "N01 G2 N34",    5,         { VN[0], VN[1] }                  },
         { L_, "N0 I1 N234",    5,         { VN[0] }                         },
         { L_, "J0 N1234",      5,         { 0 }                             },
         { L_, "N0 K1 N234",    5,         { VN[0] }                         },
         { L_, "N01 L2 N34",    5,         { VN[0], VN[1] }                  },
         { L_, "N01 M2 N34",    5,         { VN[0], VN[1] }                  },
         { L_, "N012 H3 N4",    5,         { VN[0], VN[1], VN[2] }           },
         { L_, "N0123 O4",      5,         { VN[0], VN[1], VN[2], VN[3] }    },
         { L_, "N012 P3 N4",    5,         { VN[0], VN[1], VN[2] }           },
         { L_, "N01 Q2 N34",    5,         { VN[0], VN[1] }                  },
         { L_, "N0 R1 N234",    5,         { VN[0] }                         },
         { L_, "S0 N1234",      5,         { 0 }                             },
         { L_, "N0 T1 N234",    5,         { VN[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 7: {
        // --------------------------------------------------------------------
        // GET 16-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt16(short &variable);
        //   getUint16(unsigned short &variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 16-BIT INTEGERS TEST" << endl
                                  << "========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt16'." << endl;
        {
            typedef short ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt16;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "E0123",         4,         { VE[0], VE[1], VE[2], VE[3] }    },
         { L_, "E4567",         4,         { VE[4], VE[5], VE[6], VE[7] }    },
         // streams containing incompatible data types
         { L_, "A0 E1234",      5,         { 0 }                             },
         { L_, "E0 B1 E234",    5,         { VE[0] }                         },
         { L_, "E01 C2 E34",    5,         { VE[0], VE[1] }                  },
         { L_, "E012 D3 E4",    5,         { VE[0], VE[1], VE[2] }           },
         { L_, "E0123 F4",      5,         { VE[0], VE[1], VE[2], VE[3] }    },
         { L_, "E012 G3 E4",    5,         { VE[0], VE[1], VE[2] }           },
         { L_, "E01 H2 E34",    5,         { VE[0], VE[1] }                  },
         { L_, "E0 I1 E234",    5,         { VE[0] }                         },
         { L_, "J0 E1234",      5,         { 0 }                             },
         { L_, "E0 K1 E234",    5,         { VE[0] }                         },
         { L_, "E01 L2 E34",    5,         { VE[0], VE[1] }                  },
         { L_, "E01 M2 E34",    5,         { VE[0], VE[1] }                  },
         { L_, "E012 N3 E4",    5,         { VE[0], VE[1], VE[2] }           },
         { L_, "E0123 O4",      5,         { VE[0], VE[1], VE[2], VE[3] }    },
         { L_, "E012 P3 E4",    5,         { VE[0], VE[1], VE[2] }           },
         { L_, "E01 Q2 E34",    5,         { VE[0], VE[1] }                  },
         { L_, "E0 R1 E234",    5,         { VE[0] }                         },
         { L_, "S0 E1234",      5,         { 0 }                             },
         { L_, "E0 T1 E234",    5,         { VE[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint16'." << endl;
        {
            typedef unsigned short ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint16;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "F0123",         4,         { VF[0], VF[1], VF[2], VF[3] }    },
         { L_, "F4567",         4,         { VF[4], VF[5], VF[6], VF[7] }    },
         // streams containing incompatible data types
         { L_, "A0 F1234",      5,         { 0 }                             },
         { L_, "F0 B1 F234",    5,         { VF[0] }                         },
         { L_, "F01 C2 F34",    5,         { VF[0], VF[1] }                  },
         { L_, "F012 D3 F4",    5,         { VF[0], VF[1], VF[2] }           },
         { L_, "F0123 E4",      5,         { VF[0], VF[1], VF[2], VF[3] }    },
         { L_, "F012 G3 F4",    5,         { VF[0], VF[1], VF[2] }           },
         { L_, "F01 H2 F34",    5,         { VF[0], VF[1] }                  },
         { L_, "F0 I1 F234",    5,         { VF[0] }                         },
         { L_, "J0 F1234",      5,         { 0 }                             },
         { L_, "F0 K1 F234",    5,         { VF[0] }                         },
         { L_, "F01 L2 F34",    5,         { VF[0], VF[1] }                  },
         { L_, "F01 M2 F34",    5,         { VF[0], VF[1] }                  },
         { L_, "F012 N3 F4",    5,         { VF[0], VF[1], VF[2] }           },
         { L_, "F0123 O4",      5,         { VF[0], VF[1], VF[2], VF[3] }    },
         { L_, "F012 P3 F4",    5,         { VF[0], VF[1], VF[2] }           },
         { L_, "F01 Q2 F34",    5,         { VF[0], VF[1] }                  },
         { L_, "F0 R1 F234",    5,         { VF[0] }                         },
         { L_, "S0 F1234",      5,         { 0 }                             },
         { L_, "F0 T1 F234",    5,         { VF[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 6: {
        // --------------------------------------------------------------------
        // GET 8-BIT INTEGERS TEST:
        //   Verify these methods unexternalize the expected values and verify
        //   the type check implicit to the 'bslx::TestInStream'.  See
        //   description of the testing mechanism in the above function
        //   description of 'testGetScalar'.  Note that getInt8(char&) is
        //   tested in the PRIMARY MANIPULATORS test.
        //
        // Concerns:
        //: 1 The methods unexternalize the expected values.
        //:
        //: 2 The methods implement the type check correctly.
        //
        // Plan:
        //: 1 Iterate through a set of test vectors that verify correct
        //:   behavior with valid data and correct error detection with invalid
        //:   data.  (C-1..2)
        //
        // Testing:
        //   getInt8(signed char& variable);
        //   getUint8(char& variable);
        //   getUint8(unsigned char& variable);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "GET 8-BIT INTEGERS TEST" << endl
                                  << "=======================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting 'getInt8' w/ 'signed char'." << endl;
        {
            typedef signed char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt8;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "B0123",         4,         { VB[0], VB[1], VB[2], VB[3] }    },
         { L_, "B4567",         4,         { VB[4], VB[5], VB[6], VB[7] }    },
         // streams containing incompatible data types
         { L_, "C0 B1234",      5,         { 0 }                             },
         { L_, "B0 D1 B234",    5,         { VB[0] }                         },
         { L_, "B01 E2 B34",    5,         { VB[0], VB[1] }                  },
         { L_, "B012 F3 B4",    5,         { VB[0], VB[1], VB[2] }           },
         { L_, "B0123 G4",      5,         { VB[0], VB[1], VB[2], VB[3] }    },
         { L_, "B012 H3 B4",    5,         { VB[0], VB[1], VB[2] }           },
         { L_, "B01 I2 B34",    5,         { VB[0], VB[1] }                  },
         { L_, "B0 J1 B234",    5,         { VB[0] }                         },
         { L_, "K0 B1234",      5,         { 0 }                             },
         { L_, "B0 L1 B234",    5,         { VB[0] }                         },
         { L_, "B01 M2 B34",    5,         { VB[0], VB[1] }                  },
         { L_, "B012 N3 B4",    5,         { VB[0], VB[1], VB[2] }           },
         { L_, "B0123 O4",      5,         { VB[0], VB[1], VB[2], VB[3] }    },
         { L_, "B012 P3 B4",    5,         { VB[0], VB[1], VB[2] }           },
         { L_, "B01 Q2 B34",    5,         { VB[0], VB[1] }                  },
         { L_, "B0 R1 B234",    5,         { VB[0] }                         },
         { L_, "S0 B1234",      5,         { 0 }                             },
         { L_, "B0 T1 B234",    5,         { VB[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'getUint8' w/ 'char'." << endl;
        {
            typedef char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint8;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "C0123",         4,         { VC[0], VC[1], VC[2], VC[3] }    },
         { L_, "C4567",         4,         { VC[4], VC[5], VC[6], VC[7] }    },
         // streams containing incompatible data types
         { L_, "A0 C1234",      5,         { 0 }                             },
         { L_, "C0 B1 C234",    5,         { VC[0] }                         },
         { L_, "C01 E2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C012 F3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C0123 G4",      5,         { VC[0], VC[1], VC[2], VC[3] }    },
         { L_, "C012 H3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C01 I2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C0 J1 C234",    5,         { VC[0] }                         },
         { L_, "K0 C1234",      5,         { 0 }                             },
         { L_, "C0 L1 C234",    5,         { VC[0] }                         },
         { L_, "C01 M2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C012 N3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C0123 O4",      5,         { VC[0], VC[1], VC[2], VC[3] }    },
         { L_, "C012 P3 C4",    5,         { VC[0], VC[1], VC[2] }           },
         { L_, "C01 Q2 C34",    5,         { VC[0], VC[1] }                  },
         { L_, "C0 R1 C234",    5,         { VC[0] }                         },
         { L_, "S0 C1234",      5,         { 0 }                             },
         { L_, "C0 T1 C234",    5,         { VC[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        // --------------------------------------------------------------------

        if (verbose)cout << "\nTesting 'getUint8' w/ 'unsigned char'." << endl;
        {
            typedef unsigned char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getUint8;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "D0123",         4,         { VD[0], VD[1], VD[2], VD[3] }    },
         { L_, "D4567",         4,         { VD[4], VD[5], VD[6], VD[7] }    },
         // streams containing incompatible data types
         { L_, "A0 D1234",      5,         { 0 }                             },
         { L_, "D0 B1 D234",    5,         { VD[0] }                         },
         { L_, "D01 E2 D34",    5,         { VD[0], VD[1] }                  },
         { L_, "D012 F3 D4",    5,         { VD[0], VD[1], VD[2] }           },
         { L_, "D0123 G4",      5,         { VD[0], VD[1], VD[2], VD[3] }    },
         { L_, "D012 H3 D4",    5,         { VD[0], VD[1], VD[2] }           },
         { L_, "D01 I2 D34",    5,         { VD[0], VD[1] }                  },
         { L_, "D0 J1 D234",    5,         { VD[0] }                         },
         { L_, "K0 D1234",      5,         { 0 }                             },
         { L_, "D0 L1 D234",    5,         { VD[0] }                         },
         { L_, "D01 M2 D34",    5,         { VD[0], VD[1] }                  },
         { L_, "D012 N3 D4",    5,         { VD[0], VD[1], VD[2] }           },
         { L_, "D0123 O4",      5,         { VD[0], VD[1], VD[2], VD[3] }    },
         { L_, "D012 P3 D4",    5,         { VD[0], VD[1], VD[2] }           },
         { L_, "D01 Q2 D34",    5,         { VD[0], VD[1] }                  },
         { L_, "D0 R1 D234",    5,         { VD[0] }                         },
         { L_, "S0 D1234",      5,         { 0 }                             },
         { L_, "D0 T1 D234",    5,         { VD[0] }                         },
            };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }
      } break;
      case 5: {
        // --------------------------------------------------------------------
        // PRINT OPERATOR TEST:
        //   Verify the method produces the expected output format.
        //
        // Concerns:
        //: 1 Method produces expected output format.
        //
        // Plan:
        //: 1 For a small set of objects, use 'ostringstream' to write the
        //:   object's value to a string buffer and then compare to expected
        //:   output format.  (C-1)
        //
        // Testing:
        //   ostream& operator<<(ostream&, const TestInStream&);
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "PRINT OPERATOR TEST" << endl
                                  << "===================" << endl;

        if (verbose) cout << "\nTesting print operator." << endl;

        const int SIZE = 1000;     // Must be big enough to hold output string.
        const char XX = (char) 0xFF; // Value that represents an unset char.
        char ctrl[SIZE];    memset(ctrl, XX, SIZE);
        const char *CTRL = ctrl;

        {
            Obj mX;  const Obj& X = mX;
            const char *EXPECTED = "";

            bslma::TestAllocator allocator;

            ostringstream out(bsl::string(CTRL, SIZE, &allocator), &allocator);
            out << X << ends;

            bsl::string buffer(&allocator);
            {
                bslma::DefaultAllocatorGuard allocatorGuard(&allocator);

                buffer = out.str();
            }
            const char *RESULT = buffer.c_str();

            const int LEN = static_cast<int>(strlen(EXPECTED)) + 1;
            if (veryVerbose) cout << "\tEXPECTED : " << EXPECTED << endl
                                  << "\tACTUAL : "   << RESULT   << endl;
            ASSERT(XX == RESULT[SIZE-1]); // check for overrun
            ASSERT(0 == memcmp(RESULT, EXPECTED, LEN));
            ASSERT(0 == memcmp(RESULT + LEN, CTRL + LEN, SIZE - LEN));
        }
        {
            Out o(VERSION_SELECTOR);
            o.putInt8(0);  o.putInt8(1);  o.putInt8(2);  o.putInt8(3);
            Obj mX(o.data(), o.length());  const Obj& X = mX;
            const char *EXPECTED =
                "\n0000\t" INT8_BYTE " 00 " INT8_BYTE " 01"
                       " " INT8_BYTE " 02 " INT8_BYTE " 03";

            bslma::TestAllocator allocator;

            ostringstream out(bsl::string(CTRL, SIZE, &allocator), &allocator);
            out << X << ends;

            bsl::string buffer(&allocator);
            {
                bslma::DefaultAllocatorGuard allocatorGuard(&allocator);

                buffer = out.str();
            }
            const char *RESULT = buffer.c_str();

            const int LEN = static_cast<int>(strlen(EXPECTED)) + 1;
            if (veryVerbose) cout << "\tEXPECTED : " << EXPECTED << endl
                                  << "\tACTUAL : "   << RESULT   << endl;
            ASSERT(XX == RESULT[SIZE-1]); // check for overrun
            ASSERT(0 == memcmp(RESULT, EXPECTED, LEN));
            ASSERT(0 == memcmp(RESULT + LEN, CTRL + LEN, SIZE - LEN));
        }
        {
            Out o(VERSION_SELECTOR);
            o.putInt8(0);  o.putInt8(1);  o.putInt8(2);  o.putInt8(3);
            o.putInt8(4);  o.putInt8(5);  o.putInt8(6);  o.putInt8(7);
            o.putInt8(8);  o.putInt8(9);  o.putInt8(10); o.putInt8(11);
            Obj mX(o.data(), o.length());  const Obj& X = mX;
            const char *EXPECTED =
                "\n0000\t" INT8_BYTE " 00 " INT8_BYTE " 01"
                       " " INT8_BYTE " 02 " INT8_BYTE " 03"
                "\n0008\t" INT8_BYTE " 04 " INT8_BYTE " 05"
                       " " INT8_BYTE " 06 " INT8_BYTE " 07"
                "\n0010\t" INT8_BYTE " 08 " INT8_BYTE " 09"
                       " " INT8_BYTE " 0a " INT8_BYTE " 0b";

            bslma::TestAllocator allocator;

            ostringstream out(bsl::string(CTRL, SIZE, &allocator), &allocator);
            out << X << ends;

            bsl::string buffer(&allocator);
            {
                bslma::DefaultAllocatorGuard allocatorGuard(&allocator);

                buffer = out.str();
            }
            const char *RESULT = buffer.c_str();

            const int LEN = static_cast<int>(strlen(EXPECTED)) + 1;
            if (veryVerbose) cout << "\tEXPECTED : " << EXPECTED << endl
                                  << "\tACTUAL : "   << RESULT   << endl;
            ASSERT(XX == RESULT[SIZE-1]); // check for overrun
            ASSERT(0 == memcmp(RESULT, EXPECTED, LEN));
            ASSERT(0 == memcmp(RESULT + LEN, CTRL + LEN, SIZE - LEN));
        }
      } break;
      case 4: {
        // --------------------------------------------------------------------
        // BASIC ACCESSORS TEST:
        //   Verify functionality of the basic accessors.
        //
        // Concerns:
        //: 1 The methods return correct values.
        //
        // Plan:
        //: 1 Create an empty object, use 'getInt8' and 'invalidate' to modify
        //:   state, and verify the expected values for the methods.  (C-1)
        //
        // Testing
        //   operator const void *() const;
        //   bsl::size_t cursor() const;
        //   bool isValid() const;
        //   bool isEmpty() const;
        //   bsl::size_t length() const;
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "BASIC ACCESSORS TEST" << endl
                                  << "====================" << endl;

        if (verbose) cout << "\nTesting 'operator const void *'." << endl;

        int i;

        for (i = 0; i < 3; ++i) {
            Obj mX;  const Obj& X = mX;
            int j;
            LOOP_ASSERT(i, X);

            Out o(VERSION_SELECTOR);    o.putInt8(VERSION);
            for (j = 0; j < i;  ++j) o.putInt8(j);

            Obj mX2(o.data(), o.length());  const Obj& X2 = mX2;
            bsl::size_t len = X2.length();
            LOOP_ASSERT(i, len != 0);
            if (veryVerbose) { P(X2) }
            LOOP_ASSERT(i, X2 && X2.isValid());

            LOOP_ASSERT(i, X && X2);
            LOOP_ASSERT(i, X.isValid() && X2.isValid());
            mX.invalidate();
            LOOP_ASSERT(i, !X && X2);
            LOOP_ASSERT(i, !X.isValid() && X2.isValid());

            // invalidate stream x2 by making excessive 'get' calls
            char c;
            mX2.setQuiet(1);
            for (j = 0; j < i + 10; ++j) mX2.getInt8(c);
            LOOP_ASSERT(i, !X && !X2);
            LOOP_ASSERT(i, !X.isValid() && !X2.isValid());
        }

        // --------------------------------------------------------------------

        if (verbose)
            cout << "\nTesting 'isEmpty', 'length' and 'cursor'." << endl;

        for (i = 0; i < 5; ++i) {
            // test default empty objects
            Obj mX;  const Obj& X = mX;
            int j;
            LOOP_ASSERT(i, X.isEmpty());
            LOOP_ASSERT(i, X.length() == 0);
            LOOP_ASSERT(i, X.cursor() == 0);

            // test objects of variable lengths
            Out o(VERSION_SELECTOR);    o.putInt8(VERSION);
            for (j = 0; j < i;  ++j) o.putInt8(j);

            Obj mX2(o.data(), o.length());  const Obj& X2 = mX2;
            if (veryVerbose) { P(X2) }
            LOOP_ASSERT(i, !X2.isEmpty());
            LOOP_ASSERT(i,
                        X2.length() ==
                                                    o.length());
            LOOP_ASSERT(i, X2.cursor() == 0);

            char c;
            mX2.getInt8(c);  // get version
            for (j = 0; j < i; ++j) {
                const bsl::size_t EXP =
                                 VERSION_LEN + (SIZEOF_CODE + SIZEOF_INT8) * j;
                LOOP2_ASSERT(i, j, X2.cursor() == EXP);
                mX2.getInt8(c);
            }
            LOOP_ASSERT(i, X2.isEmpty());
        }
      } break;
      case 3: {
        // --------------------------------------------------------------------
        // PRIMARY MANIPULATORS TEST:
        //   Verify functionality of primary manipulators.
        //
        // Concerns:
        //: 1 Constructors work appropriately.
        //:
        //: 2 'getInt8' produces the expected results.
        //:
        //: 3 'invalidate' produces the expected results.
        //:
        //: 4 Destructor functions properly.
        //:
        //: 5 QoI: asserted precondition violations are detected when enabled.
        //
        // Plan:
        //: 1 For 'getInt8', see documentation of the testing mechanism
        //:   'testGetScalar' for detailed information.  (C-1)
        //:
        //: 2 Create objects containing various data.
        //:
        //: 3 Modify state using 'getInt8' and 'invalidate'.
        //:
        //: 4 Verify state using basic accessors.  (C-2, C-3)
        //:
        //: 5 Since the destructor for this object is empty, the concern
        //:   regarding the destructor is trivially satisfied.  (C-4)
        //:
        //: 6 Verify defensive checks are triggered for invalid values.  (C-5)
        //
        // Testing
        //   TestInStream();
        //   TestInStream(const char *buffer, bsl::size_t numBytes);
        //   TestInStream(const bslstl::StringRef& srcData);
        //   ~TestInStream();
        //   setQuiet(int flag);
        //   getInt8(char& variable);
        //   void invalidate();
        //   bool isQuiet();
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "PRIMARY MANIPULATORS TEST" << endl
                                  << "=========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose)cout << "\nTesting 'getInt8' w/ 'char' and ctors." << endl;
        {
            typedef char ElemType;
            typedef TestInStream& (Obj::*FuncPtr)(ElemType&);
            const FuncPtr FUNC = &Obj::getInt8;

            static const ScalarTestTable<ElemType> DATA[] = {
         //                     # values   expected
         //L#  spec             to read    values
         //--  ---------------  ---------  ----------------------------------
         // read from empty stream
         { L_, "",              1,         { 0 }                             },
         // valid streams
         { L_, "A0123",         4,         { VA[0], VA[1], VA[2], VA[3] }    },
         { L_, "A4567",         4,         { VA[4], VA[5], VA[6], VA[7] }    },
         // streams containing incompatible data types
         { L_, "C0 A1234",      5,         { 0 }                             },
         { L_, "A0 D1 A234",    5,         { VA[0] }                         },
         { L_, "A01 E2 A34",    5,         { VA[0], VA[1] }                  },
         { L_, "A012 F3 A4",    5,         { VA[0], VA[1], VA[2] }           },
         { L_, "A0123 G4",      5,         { VA[0], VA[1], VA[2], VA[3] }    },
         { L_, "A012 H3 A4",    5,         { VA[0], VA[1], VA[2] }           },
         { L_, "A01 I2 A34",    5,         { VA[0], VA[1] }                  },
         { L_, "A0 J1 A234",    5,         { VA[0] }                         },
         { L_, "K0 A1234",      5,         { 0 }                             },
         { L_, "A0 L1 A234",    5,         { VA[0] }                         },
        };
            const int DATA_LEN = static_cast<int>(sizeof DATA / sizeof *DATA);

            testGetScalar<ElemType, FuncPtr>(DATA, DATA_LEN, FUNC);
        }

        {
            // Test default constructor.

            Obj x0;
            if (veryVerbose) { P(x0) }
            ASSERT(x0);
            ASSERT(0 == x0.length());
        }
        {
            // Test constructor initialized with a 'char *'.

            Out o(VERSION_SELECTOR);
            o.putInt8(1);
            o.putInt8(2);
            o.putInt8(3);
            o.putInt8(4);

            Obj mX(o.data(), o.length());  const Obj& X = mX;
            ASSERT(X);
            ASSERT(X.length() == o.length());
            if (veryVerbose) { P(X) }
            char val;
            mX.getInt8(val);              ASSERT(1 == val);
            mX.getInt8(val);              ASSERT(2 == val);
            mX.getInt8(val);              ASSERT(3 == val);
            mX.getInt8(val);              ASSERT(4 == val);
            ASSERT(X);
            ASSERT(X.isEmpty());
            ASSERT(X.cursor() == X.length());
        }
        {
            // Test constructor initialized with a 'bslstl::StringRef'.

            Out o(VERSION_SELECTOR);
            o.putInt8(5);
            o.putInt8(6);
            o.putInt8(7);
            o.putInt8(8);

            bslstl::StringRef srcData(o.data(), static_cast<int>(o.length()));

            Obj mX(srcData);  const Obj& X = mX;
            ASSERT(X);
            ASSERT(X.length() == o.length());
            if (veryVerbose) { P(X) }
            char val;
            mX.getInt8(val);              ASSERT(5 == val);
            mX.getInt8(val);              ASSERT(6 == val);
            mX.getInt8(val);              ASSERT(7 == val);
            mX.getInt8(val);              ASSERT(8 == val);
            ASSERT(X);
            ASSERT(X.isEmpty());
            ASSERT(X.cursor() == X.length());
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting 'invalidate'." << endl;
        for (int i = 0; i < 5; ++i) {
            // test default objects
            Obj mX;  const Obj& X = mX;
            LOOP_ASSERT(i, X);
            mX.invalidate();
            LOOP_ASSERT(i, !X);

            // test objects of variable lengths
            Out o(VERSION_SELECTOR);    o.putInt8(VERSION);
            for (int j = 0; j < i;  ++j) o.putInt8(j);

            Obj mX2(o.data(), o.length());  const Obj& X2 = mX2;
            if (veryVerbose) { P(X2) }
            LOOP_ASSERT(i, X2);
            mX2.invalidate();
            LOOP_ASSERT(i, !X2);
        }

        // --------------------------------------------------------------------

        if (verbose) cout << "\nTesting get/set flags" << endl;
        {
            Obj mX;  const Obj& X = mX;
            ASSERT(0 == X.isQuiet());

            if (verbose) cout << "\tQuiet" << endl;
            mX.setQuiet(10);
            ASSERT(1 == X.isQuiet());
            mX.setQuiet(0);
            ASSERT(0 == X.isQuiet());
        }

        // --------------------------------------------------------------------

        if (verbose)
            cout << "\nNegative Testing." << endl;
        {
            bsls::AssertTestHandlerGuard guard;

            ASSERT_SAFE_PASS(Obj mX(0, 0));
            ASSERT_FAIL(Obj mX(0, 1));
        }
      } break;
      case 2: {
        // --------------------------------------------------------------------
        // GENERATOR FUNCTION 'g' TEST:
        //   Verify behavior of the 'g' function.
        //
        // Concerns:
        //: 1 Generator function works correctly.
        //
        // Plan:
        //: 1 Perform independent tests with spec strings representative of the
        //    different possible formats for the 'g' function: generate
        //    "control" objects manually configured with the same sequence of
        //    operations as specified in the spec string and verify the
        //    resulting output stream object configured by the 'g' function
        //    contains the same content as the "control" object.  (C-1)
        //
        // Testing:
        //   int g(Out* o, const char* spec)
        // --------------------------------------------------------------------
        if (verbose) cout << endl << "Generator Function 'g' TEST" << endl
                                  << "===========================" << endl;

        if (verbose) cout << endl
            << "Note:" << endl
            << "  Error messages can be viewed in veryVerbose mode" << endl;

        if (verbose) cout << "\nTesting empty spec." << endl;
        {
            const char *SPEC = "";
            const Out X(VERSION_SELECTOR);

            Out o(VERSION_SELECTOR);
            int res = g(&o, SPEC);
            if (veryVerbose) { P(o) }
            ASSERT(1 == res);
            ASSERT(X.length() == o.length());
            ASSERT(0 == memcmp(X.data(),
                               o.data(),
                               X.length()));
        }
        if (verbose) cout << "\nTesting spec w/ single operation." << endl;
        {
            const char *SPEC = "A012";
            if (veryVerbose) cout << "\tSPEC : \"" << SPEC << '"' << endl;
            Out mX(VERSION_SELECTOR);    const Out& X = mX;
            mX.putInt8(VA[0]);
            mX.putInt8(VA[1]);
            mX.putInt8(VA[2]);

            Out o(VERSION_SELECTOR);
            int res = g(&o, SPEC);
            if (veryVerbose) { P(o); }
            ASSERT(1 == res);
            ASSERT(X.length() == o.length());
            ASSERT(0 == memcmp(X.data(),
                               o.data(),
                               X.length()));
        }
        if (verbose) cout << "\nTesting spec w/ spaces." << endl;
        {
            const char *SPEC = "  A01 \t 2  A3 \t";
            if (veryVerbose) cout << "\tSPEC : \"" << SPEC << '"' << endl;
            Out mX(VERSION_SELECTOR);    const Out& X = mX;
            mX.putInt8(VA[0]);
            mX.putInt8(VA[1]);
            mX.putInt8(VA[2]);
            mX.putInt8(VA[3]);

            Out o(VERSION_SELECTOR);
            int res = g(&o, SPEC);
            if (veryVerbose) { P(o); }
            ASSERT(1 == res);
            ASSERT(X.length() == o.length());
            ASSERT(0 == memcmp(X.data(),
                               o.data(),
                               X.length()));
        }
        if (verbose) cout << "\nTesting spec w/ multiple operations." << endl;
        {
            const char *SPEC = "A0 B12 C0 D12 E345 F67 G8 H90 I123 J45 K6 L78";
            if (veryVerbose) cout << "\tSPEC : \"" << SPEC << '"' << endl;
            Out mX(VERSION_SELECTOR);    const Out& X = mX;
            mX.putInt8(VA[0]);
            mX.putInt8(VB[1]);     mX.putInt8(VB[2]);
            mX.putUint8(VC[0]);
            mX.putUint8(VD[1]);    mX.putUint8(VD[2]);
            mX.putInt16(VE[3]);    mX.putInt16(VE[4]);    mX.putInt16(VE[5]);
            mX.putUint16(VF[6]);   mX.putUint16(VF[7]);
            mX.putInt32(VG[8]);
            mX.putUint32(VH[9]);   mX.putUint32(VH[0]);
            mX.putInt64(VI[1]);    mX.putInt64(VI[2]);    mX.putInt64(VI[3]);
            mX.putUint64(VJ[4]);   mX.putUint64(VJ[5]);
            mX.putFloat32(VK[6]);
            mX.putFloat64(VL[7]);  mX.putFloat64(VL[8]);

            Out o(VERSION_SELECTOR);
            int res = g(&o, SPEC);
            if (veryVerbose) { P(o); }
            ASSERT(1 == res);
            ASSERT(X.length() == o.length());
            ASSERT(0 == memcmp(X.data(),
                               o.data(),
                               X.length()));
        }
        if (verbose)
            cout << "\nTesting spec w/ single array operation." << endl;
        {
            int i;
            // test spec's of "a0", "a1", "a2"...
            for (i = 0; i < 3; ++i) {
                static char spec[10];    memset((void *) spec, 0, 10);
                sprintf(spec, "a%d", i);
                if (veryVerbose) cout << "\tSPEC : \"" << spec << '"' << endl;
                Out mX(VERSION_SELECTOR);    const Out& X = mX;
                mX.putArrayInt8(VA, i);

                Out o(VERSION_SELECTOR);
                int res = g(&o, spec);
                if (veryVerbose) { P(o); }
                ASSERT(1 == res);
                ASSERT(X.length() == o.length());
                ASSERT(0 == memcmp(X.data(),
                                   o.data(),
                                   X.length()));
            }

            const char *SPEC = "a012";
            if (veryVerbose) cout << "\tSPEC : \"" << SPEC << '"' << endl;
            Out mX(VERSION_SELECTOR);    const Out& X = mX;
            for (i = 0; i < 3; ++i) mX.putArrayInt8(VA, i);

            Out o(VERSION_SELECTOR);
            int res = g(&o, SPEC);
            if (veryVerbose) { P(o); }
            ASSERT(1 == res);
            ASSERT(X.length() == o.length());
            ASSERT(0 == memcmp(X.data(),
                               o.data(),
                               X.length()));
        }
        if (verbose)
            cout << "\nTesting spec w/ multiple array operations." << endl;
        {
            const char *SPEC = "a1 b2 c2 d2 e3 f4 g5 h6 i7 j8 k9 l1";
            if (veryVerbose) cout << "\tSPEC : \"" << SPEC << '"' << endl;
            Out mX(VERSION_SELECTOR);    const Out& X = mX;
            mX.putArrayInt8(VA, 1);
            mX.putArrayInt8(VB, 2);
            mX.putArrayUint8(VC, 2);
            mX.putArrayUint8(VD, 2);
            mX.putArrayInt16(VE, 3);
            mX.putArrayUint16(VF, 4);
            mX.putArrayInt32(VG, 5);
            mX.putArrayUint32(VH, 6);
            mX.putArrayInt64(VI, 7);
            mX.putArrayUint64(VJ, 8);
            mX.putArrayFloat32(VK, 9);
            mX.putArrayFloat64(VL, 1);

            Out o(VERSION_SELECTOR);
            int res = g(&o, SPEC);
            if (veryVerbose) { P(o); }
            ASSERT(1 == res);
            ASSERT(X.length() == o.length());
            ASSERT(0 == memcmp(X.data(),
                               o.data(),
                               X.length()));
        }
        if (verbose) cout << "\nTesting invalid specs." << endl;
        {
            const char *SPEC[] = {
                "a",
                "1",
                "a1 b2 Cf3 F4",
                "A0 B2 CC",
                "1A B2 E3"
                };
            const int NUM_TEST = static_cast<int>(sizeof SPEC / sizeof *SPEC);
            for (int i = 0; i < NUM_TEST; ++i) {
                if (veryVerbose)
                    cout << "\tSPEC : \"" << SPEC[i] << '"' << endl;
                Out o(VERSION_SELECTOR);
                int res = g(&o, SPEC[i]);
                if (veryVerbose) { P(o); }
                ASSERT(0 == res);
            }
        }
      } break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST:
        //   This case exercises (but does not fully test) basic functionality.
        //
        // Concerns:
        //: 1 The class is sufficiently functional to enable comprehensive
        //:   testing in subsequent test cases.
        //
        // Plan:
        //: 1 Create 'TestInStream' objects using default and buffer
        //:   constructors.
        //:
        //: 2 Exercise these objects using various methods.
        //:
        //: 3 Verify expected values throughout.  (C-1)
        //
        // Testing:
        //   BREATHING TEST
        // --------------------------------------------------------------------

        if (verbose) cout << endl << "BREATHING TEST" << endl
                                  << "==============" << endl;

        if (verbose) cout << "\nCreate object mX1 using default ctor." << endl;
        Obj mX1;  const Obj& X1 = mX1;
        ASSERT(0 == X1.length());

        if (verbose) cout << "\nCreate object mX2 w/ an initial value."
                          << endl;
        int i;
        Out o(VERSION_SELECTOR);    o.putInt8(VERSION);
        for (i = 0; i < 5; ++i) o.putInt8(i);
        Obj mX2(o.data(), o.length());  const Obj& X2 = mX2;
        if (veryVerbose) { P(X2); }
        ASSERT(o.length() == X2.length());

        if (verbose) cout << "\nTry getInt8() with x2." << endl;
        char c;     mX2.getInt8(c);  // get version
        for (i = 0; i < 5; ++i) {
            mX2.getInt8(c);
            LOOP2_ASSERT(i, (int)c, i == c);
        }

        if (verbose) cout << "\nTry isEmpty() with x2." << endl;
        ASSERT(1 == X2.isEmpty());

        if (verbose) cout << "\nTry invalidate() with x2." << endl;
        mX2.invalidate();
        ASSERT(!X2);

        if (verbose) cout << "\nTry invalid operation with x1." << endl;
        mX1.setQuiet(1);

        mX1.getInt32(i);
        ASSERT(!X1);
      } break;
      default: {
        cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl;
        testStatus = -1;
      }
    }

    if (testStatus > 0) {
        cerr << "Error, non-zero test status = " << testStatus << "." << endl;
    }
    return testStatus;
}

// ----------------------------------------------------------------------------
// Copyright 2014 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
